### numpy版本为1.20.3import 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为0b = 0return W, b
- X: 输入特征矩阵,大小为 m×n,其中 m 是样本数量,n 是特征数量。
- y: 输出标签向量,大小为 m×1,包含每个样本的真实标签(0或1)。
- W: 权值参数,大小为 n×1,代表特征权重。
- 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.0return a, cost, dW, db#返回逻辑回归模型输出、损失、权值梯度、偏置梯度
模型输出(a)的计算:使用sigmoid函数作为激活函数,计算模型的输出。公式为 ,其中 σ 是sigmoid函数,它将线性回归输出转换为概率值(介于0和1之间)。
交叉熵损失(cost)的计算:使用交叉熵损失函数来衡量模型预测值与真实值之间的差异。对于二分类问题,交叉熵损失的公式为 ,其中 m 是样本数量。这个损失函数针对每个样本计算预测值与实际值的差异,然后取平均值。
权值梯度(dW)和偏置梯度(db)的计算:这两个梯度用于根据损失函数的梯度下降法更新权值和偏置。权值梯度计算公式为 ,偏置梯度计算公式为 。这里,是特征矩阵的转置,确保梯度与权重矩阵的维度一致。
损失压缩:最后,使用
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 * dWb = 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] = 1else:y_prediction[i] = 0return y_prediction
输入参数
- X: 输入特征矩阵,大小m×n,其中 m 是样本数量,n 是特征数量。这代表要进行预测的新数据集。
- params: 训练好的模型参数,是一个字典,包含了权重 W 和偏置 b。其中,W 是权值参数,大小为 n×1,而 b 是偏置参数,是一个标量。
输出参数
- y_prediction: 转换后的模型预测值,是一个大小为 m×1 的向量,包含了对每个样本的二分类预测结果(0或1)。
模型预测值的计算:首先,函数使用sigmoid函数计算模型的预测概率。这一步是通过对输入特征矩阵 X 和模型参数 W 进行矩阵乘法,然后加上偏置 b,并将结果通过sigmoid函数转换为概率值。计算公式为 ,其中 σ 是sigmoid函数。
概率到分类的转换:接下来,函数遍历预测概率向量 ,将每个概率值与分类阈值(通常为0.5)进行比较。如果概率值大于0.5,则将该样本的预测类别设置为1(表示属于正类);如果概率值小于或等于0.5,则将预测类别设置为0(表示属于负类)。这个步骤将连续的概率预测转换为明确的类别预测,便于后续的分类任务。
返回预测结果:最后,函数返回转换后的预测值 。
# 导入matplotlib绘图库import matplotlib.pyplot as plt# 导入生成分类数据函数# from sklearn.datasets.samples_generator import make_classificationfrom 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 = 0for 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 +=1accuracy_score = correct_count / len(y_test)return accuracy_scoreaccuracy_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 LogisticRegressionclf = LogisticRegression(random_state=0).fit(X_train, y_train)y_pred = clf.predict(X_test)print(classification_report(y_test, y_pred))