机器学习复习(8)——逻辑回归

发布于:2024-03-03 ⋅ 阅读:(54) ⋅ 点赞:(0)

### numpy版本为1.20.3
import numpy as np

### 定义sigmoid函数
def sigmoid(x):
    z = 1 / (1 + np.exp(-x))
    return z

# 定义参数初始化函数
def initialize_params(dims):
    W = np.zeros((dims, 1))#初始化W为0
    b = 0
    return W, b
  1. X: 输入特征矩阵,大小为 m×n,其中 m 是样本数量,n 是特征数量。
  2. y: 输出标签向量,大小为 m×1,包含每个样本的真实标签(0或1)。
  3. W: 权值参数,大小为 n×1,代表特征权重。
  4. b: 偏置参数,是一个标量,代表模型的偏置项。

 

### 定义对数几率回归模型主体
def logistic(X, y, W, b):
    '''
    输入:
    X: 输入特征矩阵
    y: 输出标签向量
    W: 权值参数
    b: 偏置参数
    输出:
    a: 逻辑回归模型输出
    cost: 损失
    dW: 权值梯度
    db: 偏置梯度
    '''
    # 训练样本量
    num_train = X.shape[0]
    # 训练特征数
    num_feature = X.shape[1]
    # 逻辑回归模型输出
    a = sigmoid(np.dot(X, W) + b)
    # 交叉熵损失
    cost = -1/num_train * np.sum(y*np.log(a) + (1-y)*np.log(1-a))
    # 权值梯度
    dW = np.dot(X.T, (a-y))/num_train#dot()函数是矩阵乘法,eg:[n,m]@[m,p]=[n,p]
    # 偏置梯度
    db = np.sum(a-y)/num_train
    # 压缩损失数组维度
    cost = np.squeeze(cost) #压缩损失值的维度,以确保输出的损失值是一个标量而不是一个数组。例如:[[3.]]变成了3.0
    return a, cost, dW, db#返回逻辑回归模型输出、损失、权值梯度、偏置梯度

 

  • 模型输出(a)的计算:使用sigmoid函数作为激活函数,计算模型的输出。公式为 a=\sigma(XW+b),其中 σ 是sigmoid函数,它将线性回归输出转换为概率值(介于0和1之间)。

  • 交叉熵损失(cost)的计算:使用交叉熵损失函数来衡量模型预测值与真实值之间的差异。对于二分类问题,交叉熵损失的公式为 -\frac1m\sum_{i=1}^m[y^{(i)}\log(a^{(i)})+(1-y^{(i)})\log(1-a^{(i)})],其中 m 是样本数量。这个损失函数针对每个样本计算预测值与实际值的差异,然后取平均值。

  • 权值梯度(dW)和偏置梯度(db)的计算:这两个梯度用于根据损失函数的梯度下降法更新权值和偏置。权值梯度计算公式为 dW=\frac1mX^T(a-y),偏置梯度计算公式为 db=\frac1m\sum_{i=1}^m(a^{(i)}-y^{(i)})。这里,X^{T}是特征矩阵的转置,确保梯度与权重矩阵的维度一致。

  • 损失压缩:最后,使用 np.squeeze(cost) 压缩损失值的维度,以确保输出的损失值是一个标量而不是一个数组。

### 定义对数几率回归模型训练过程
def logistic_train(X, y, learning_rate, epochs):
    '''
    输入:
    X: 输入特征矩阵
    y: 输出标签向量
    learning_rate: 学习率
    epochs: 训练轮数
    输出:
    cost_list: 损失列表
    params: 模型参数
    grads: 参数梯度
    '''
    # 初始化模型参数
    W, b = initialize_params(X.shape[1])  #X.shape[1]表示特征数
    # 初始化损失列表
    cost_list = []  
    
    # 迭代训练
    for i in range(epochs):
        # 计算当前次的模型计算结果、损失和参数梯度
        a, cost, dW, db = logistic(X, y, W, b)    
        # 参数更新
        W = W -learning_rate * dW
        b = b -learning_rate * db        
        # 记录损失
        if i % 100 == 0:
            cost_list.append(cost)   
        # 打印训练过程中的损失 
        if i % 100 == 0:
            print('epoch %d cost %f' % (i, cost)) 
               
    # 保存参数
    params = {            
        'W': W,            
        'b': b
    }        

    # 保存梯度
    grads = {            
        'dW': dW,            
        'db': db
    }                
    return cost_list, params, grads
### 定义预测函数
def predict(X, params):
    '''
    输入:
    X: 输入特征矩阵
    params: 训练好的模型参数
    输出:
    y_prediction: 转换后的模型预测值
    '''
    # 模型预测值
    y_prediction = sigmoid(np.dot(X, params['W']) + params['b'])#模型预测值
    # 基于分类阈值对概率预测值进行类别转换
    for i in range(len(y_prediction)):        
        if y_prediction[i] > 0.5:
            y_prediction[i] = 1
        else:
            y_prediction[i] = 0
            
    return y_prediction

 

输入参数

  1. X: 输入特征矩阵,大小m×n,其中 m 是样本数量,n 是特征数量。这代表要进行预测的新数据集。
  2. params: 训练好的模型参数,是一个字典,包含了权重 W 和偏置 b。其中,W 是权值参数,大小为 n×1,而 b 是偏置参数,是一个标量。

输出参数

  • y_prediction: 转换后的模型预测值,是一个大小为 m×1 的向量,包含了对每个样本的二分类预测结果(0或1)。
  • 模型预测值的计算:首先,函数使用sigmoid函数计算模型的预测概率。这一步是通过对输入特征矩阵 X 和模型参数 W 进行矩阵乘法,然后加上偏置 b,并将结果通过sigmoid函数转换为概率值。计算公式为y_{\text{prediction}}= \sigma ( X W + b ) ,其中 σ 是sigmoid函数。

  • 概率到分类的转换:接下来,函数遍历预测概率向量 y_{\text{prediction}},将每个概率值与分类阈值(通常为0.5)进行比较。如果概率值大于0.5,则将该样本的预测类别设置为1(表示属于正类);如果概率值小于或等于0.5,则将预测类别设置为0(表示属于负类)。这个步骤将连续的概率预测转换为明确的类别预测,便于后续的分类任务。

  • 返回预测结果:最后,函数返回转换后的预测值 y_{\text{prediction}}

# 导入matplotlib绘图库
import matplotlib.pyplot as plt
# 导入生成分类数据函数
# from sklearn.datasets.samples_generator import make_classification
from sklearn.datasets import make_classification
# 生成100*2的模拟二分类数据集
X, labels = make_classification(
    n_samples=100,
    n_features=2,
    n_redundant=0,
    n_informative=2,
    random_state=1,
    n_clusters_per_class=2)

# 设置随机数种子
rng = np.random.RandomState(2)
# 对生成的特征数据添加一组均匀分布噪声
X += 2 * rng.uniform(size=X.shape)
# 标签类别数
unique_lables = set(labels)
# 根据标签类别数设置颜色
colors = plt.cm.Spectral(np.linspace(0,1,len(unique_lables)))
# 绘制模拟数据的散点图
for k,col in zip(unique_lables, colors):
    x_k=X[labels==k]
    plt.plot(x_k[:,0],x_k[:,1],'o',markerfacecolor=col,markeredgecolor="k",
             markersize=14)
plt.title('Simulated binary data set')
plt.show();

 

print(X.shape, labels.shape)

labels = labels.reshape((-1, 1))
data = np.concatenate((X, labels), axis=1)
print(data.shape)

# 训练集与测试集的简单划分
offset = int(X.shape[0] * 0.9)
X_train, y_train = X[:offset], labels[:offset]
X_test, y_test = X[offset:], labels[offset:]
y_train = y_train.reshape((-1,1))
y_test = y_test.reshape((-1,1))

print('X_train=', X_train.shape)
print('X_test=', X_test.shape)
print('y_train=', y_train.shape)
print('y_test=', y_test.shape)

cost_list, params, grads = logistic_train(X_train, y_train, 0.01, 1000)


y_pred = predict(X_test, params)
print(y_pred)


sigmoid(np.dot(X_test, params['W']) + params['b'])

from sklearn.metrics import accuracy_score, classification_report
# print(accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred))


def accuracy(y_test, y_pred):
    correct_count = 0
    for i in range(len(y_test)):
        for j in range(len(y_pred)):
            if y_test[i] == y_pred[j] and i == j:
                correct_count +=1
            
    accuracy_score = correct_count / len(y_test)
    return accuracy_score

accuracy_score_test = accuracy(y_test, y_pred)
print(accuracy_score_test)


y_train_pred = predict(X_train, params)
accuracy_score_train = accuracy(y_train, y_train_pred)
print(accuracy_score_train)


### 绘制逻辑回归决策边界
def plot_decision_boundary(X_train, y_train, params):
    '''
    输入:
    X_train: 训练集输入
    y_train: 训练集标签
    params:训练好的模型参数
    输出:
    决策边界图
    '''
    # 训练样本量
    n = X_train.shape[0]
    # 初始化类别坐标点列表
    xcord1 = []
    ycord1 = []
    xcord2 = []
    ycord2 = []
    # 获取两类坐标点并存入列表
    for i in range(n):
        if y_train[i] == 1:
            xcord1.append(X_train[i][0])
            ycord1.append(X_train[i][1])
        else:
            xcord2.append(X_train[i][0])
            ycord2.append(X_train[i][1])
    # 创建绘图
    fig = plt.figure()
    ax = fig.add_subplot(111)
    # 绘制两类散点,以不同颜色表示
    ax.scatter(xcord1, ycord1,s=32, c='red')
    ax.scatter(xcord2, ycord2, s=32, c='green')
    # 取值范围
    x = np.arange(-1.5, 3, 0.1)
    # 决策边界公式
    y = (-params['b'] - params['W'][0] * x) / params['W'][1]
    # 绘图
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()
    
plot_decision_boundary(X_train, y_train, params)


from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(random_state=0).fit(X_train, y_train)
y_pred = clf.predict(X_test)

print(classification_report(y_test, y_pred))


网站公告

今日签到

点亮在社区的每一天
去签到