本篇内容为《机器学习实战》第 5 章 Logistic 回归程序清单。
书中所用代码为 python2,下面给出的程序清单是在 python3 中实践改过的代码,希望对你有帮助。
训练算法:使用梯度上升找到最佳参数
梯度上升法的伪代码如下:
每个回归系数初始化为 1
重复 R 次:————计算整个数据集的梯度————使用 alpha $\times$ gradient 更新回归系数的向量返回回归系数程序清单 5-1:Logisitc 回归梯度上升优化算法
# 打开文本文件 testSet.txt 并逐行读取def loadDataSet(): dataMat = []; lableMat = [] fr = open('testSet.txt') for line in fr.readlines(): lineArr = line.strip().split() # 为计算方便,将 X0 的值设为 1.0 dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) lableMat.append(int(lineArr[2])) return dataMat, lableMatdef sigmoid(intX): return 1.0/(1+exp(-intX))# 参数 dataMatIn 是一个 2 维 numpy 数组,存放的是一个 100*3 的矩阵# 每列分别代表每个不同的特征,每行代表每个训练样本def gradAscent(dataMatIn, classLabels): # 转换为 numpy 矩阵的数据类型 dataMatrix = mat(dataMatIn) # classLabels 类别标签 labelMat = mat(classLabels).transpose() # 得到矩阵大小 m,n = shape(dataMatrix) # 设置梯度上升法所需参数 # alpha 步长,maxCycles 迭代次数 alpha = 0.001 maxCycles = 500 weights = ones((n,1)) for k in range(maxCycles): h = sigmoid(dataMatrix * weights) # 计算真实类别与预测类的差值,然后按照该差值的方向调整回归系数 error = (labelMat - h) weights = weights + alpha * dataMatrix.transpose() * error # 返回训练好的回归系数 return weights
在 python 提示符下,执行代码并得到结果:
>>> import logRegres>>> dataArr, labelMat=logRegres.loadDataSet()>>> logRegres.gradAscent(dataArr, labelMat)matrix([[ 4.12414349], [ 0.48007329], [-0.6168482 ]])
分析数据:画出决策边界
程序清单 5-2:画出数据集和 Logistic 回归最佳拟合直线的函数
# 画出数据集和logistic回归最佳拟合直线的函数def plotBestFit(weights): import matplotlib.pyplot as plt dataMat, labelMat = loadDataSet() dataArr = array(dataMat) n = shape(dataArr)[0] xcord1 = [] ycord1 = [] xcord2 = [] ycord2 = [] for i in range(n): if int(labelMat[i]) == 1: xcord1.append(dataArr[i,1]) ycord1.append(dataArr[i,2]) else: xcord2.append(dataArr[i,1]) ycord2.append(dataArr[i,2]) fig = plt.figure() ax = fig.add_subplot(111) # 形状参数 marker 's':正方形,参数 s:点的大小 ax.scatter(xcord1, ycord1, s=30, c='red', marker='s') ax.scatter(xcord2, ycord2, s=30, c='green') # arange(start, end, step),返回一个array对象 x = arange(-3.0, 3.0, 0.1) # 设置 sigmoid 函数为0 y = (-weights[0]-weights[1]*x)/weights[2] ax.plot(x, y) plt.xlabel('X1') plt.ylabel('X2') plt.show()
在 python 提示符下,执行代码并得到结果:
>>> import importlib>>> importlib.reload(logRegres)>>> weights = logRegres.gradAscent(dataArr, labelMat)>>> logRegres.plotBestFit(weights.getA())
训练算法:随机梯度上升
随机梯度上升算法的伪代码如下:
所有回归系数初始化为 1对数据集中每个样本————计算该样本的梯度————使用 alpha $\times$ gradient 更新回归系数值返回回归系数值程序清单 5-3:随机梯度上升算法
# 随机梯度上升算法def stocGradAscent0(dataMatrix, classLabels): m,n = shape(dataMatrix) alpha = 0.01 weights = ones(n) for i in range(m): # 变量 h 和误差 error 都是向量 h = sigmoid(sum(dataMatrix[i]*weights)) error = classLabels[i] - h weights = weights + alpha * error * dataMatrix[i] return weights
在 python 提示符下,执行代码并得到结果:
>>> from numpy import *>>> importlib.reload(logRegres)>>> dataArr, labelMat=logRegres.loadDataSet()>>> weights = logRegres.stocGradAscent0(array(dataArr), labelMat)>>> logRegres.plotBestFit(weights)
程序清单 5-4:改进的随机梯度上升算法
# 改进的随机梯度上升算法def stocGradAscent1(dataMatrix, classLabels, numIter=150): m,n = shape(dataMatrix) weights = ones(n) for j in range(numIter): dataIndex = list(range(m)) for i in range(m): alpha = 4/(1.0+j+i)+0.01 # uniform() 方法将随机生成下一个实数 randIndex = int(random.uniform(0, len(dataIndex))) h = sigmoid(sum(dataMatrix[randIndex]*weights)) error = classLabels[randIndex] - h weights = weights + alpha * error * dataMatrix[randIndex] del(dataIndex[randIndex]) return weights
在 python 提示符下,执行代码并得到结果:
>>> importlib.reload(logRegres)>>> dataArr, labelMat=logRegres.loadDataSet()>>> weights = logRegres.stocGradAscent1(array(dataArr), labelMat)>>> logRegres.plotBestFit(weights)
示例:从疝气病症预测病马的死亡率
使用 Logistic 回归估计马疝病的死亡率
- 收集数据:给定数据文件。
- 准备数据:用 Python 解析文本文件并填充缺失值。
- 分析数据:可视化并观察数据。
- 训练算法:使用优化算法,找到最佳的系数。
- 测试算法:为了量化回归的效果,需要观察错误率。根据错误率决定是否回退到训练阶段,通过改变迭代的次数和步长等参数来得到更好的回归系数。
- 使用算法:实现一个简单的命令行程序来收集马的症状并输出预测结果。
使用 Logistic 回归方法进行分类所需做的是把测试集上每个特征向量乘以最优化方法得来的回归系数,再将该乘积结果求和,最后输入到 sigmoid 函数即可。如果对应的 sigmoid 值大于 0.5 就预测类别标签为 1,否则为 0。
程序清单 5-5:Logistic 回归分类函数
# 以回归系数和特征向量作为输入来计算对应的 sigmoid 值def classifyVector(inX, weights): prob = sigmoid(sum(inX*weights)) if prob > 0.5: return 1.0 else: return 0.0# 打开测试集和训练集,并对数据进行格式化处理def colicTest(): frTrain = open('horseColicTraining.txt') frTest = open('horseColicTest.txt') trainingSet = [] trainingLabels = [] for line in frTrain.readlines(): currLine = line.strip().split('\t') lineArr = [] for i in range(21): lineArr.append(float(currLine[i])) trainingSet.append(lineArr) trainingLabels.append(float(currLine[21])) # 计算回归系数向量 trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 500) errorCount = 0 numTestVec = 0.0 # 导入测试集并计算分类错误率 for line in frTest.readlines(): numTestVec += 1.0 currLine = line.strip().split('\t') lineArr = [] for i in range(21): lineArr.append(float(currLine[i])) if int(classifyVector(array(lineArr), trainWeights)) !=int(currLine[21]): errorCount += 1 errorRate = (float(errorCount) / numTestVec) print('这个测试集的错误率是:%f' % errorRate) return errorRatedef multiTest(): numTests = 10 errorSum = 0.0 for k in range(numTests): errorSum += colicTest() print('经过 %d 次迭代后平均错误率是:%f' % (numTests, errorSum/float(numTests)))
在 python 提示符下,执行代码并得到结果:
>>> importlib.reload(logRegres)>>> logRegres.multiTest()这个测试集的错误率是:0.358209这个测试集的错误率是:0.373134这个测试集的错误率是:0.253731这个测试集的错误率是:0.402985这个测试集的错误率是:0.358209这个测试集的错误率是:0.298507这个测试集的错误率是:0.343284这个测试集的错误率是:0.298507这个测试集的错误率是:0.402985这个测试集的错误率是:0.417910经过 10 次迭代后平均错误率是:0.350746
Logistic 回归的目的是寻找一个非线性函数 sigmoid 的最佳拟合参数,求解过程可以由最优化算法来完成。
不足之处,欢迎指正。
$$$$