本系列主要参考《机器学习实战》,使用python3编译环境,实现书中的相关代码。
1.基本算法
关于梯度上升算法和随机梯度上升算法的选择:
当数据集较小时,使用梯度上升算法;
当数据集较大时,使用改进的随机梯度上升算法。
1 """ 2 使用梯度上升和随机梯度上升,解决逻辑回归 3 数据的显示 4 """ 5 6 import numpy as np 7 import matplotlib.pyplot as plt 8 import random 9 """ 10 加载数据 11 """ 12 def loadDataSet(): 13 dataMat = [] #数据列表 14 labelMat = [] #标签列表 15 fr = open('testSet.txt') 16 for line in fr.readlines(): 17 #print(line) 18 lineArr = line.strip().split() #去回车,放入列表 19 dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #添加数据 20 labelMat.append(int(lineArr[2])) #添加标签 21 fr.close() 22 return dataMat,labelMat 23 24 """ 25 绘制数据 26 """ 27 def plotDataSet(): 28 dataMat,labelMat=loadDataSet() 29 dataArr = np.array(dataMat) #将list或tuple变量转换成numpy的array数组 30 n = np.shape(dataMat)[0] #numpy.shape返回数组每一维的大小 31 xcord1 = []; ycord1 = [] #正样本 32 xcord2 = []; ycord2 = [] #负样本 33 for i in range(n): #将样本集分类 34 if int(labelMat[i]) == 1: 35 xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) 36 else: 37 xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) 38 39 fig = plt.figure() 40 ax = fig.add_subplot(111) #添加subplot 41 ax.scatter(xcord1,ycord1,s = 20 , c='red', marker = 's',alpha=0.5) #绘制正样本 42 ax.scatter(xcord2,ycord2,s = 20 , c='green', alpha=0.5) #绘制负样本 43 plt.title("DataSet") #绘制title 44 plt.xlabel('x1'); plt.ylabel('x2') #绘制label 45 plt.show() #显示 46 47 """ 48 sigmoid函数 49 """ 50 def sigmoid(inX): 51 return 1.0/(1 + np.exp(-inX)) 52 53 """ 54 梯度上升算法 55 """ 56 def gradientAscent(dataMatIn,classLabels): 57 dataMatrix = np.mat(dataMatIn) #转换为numpy矩阵 58 labelMat = np.mat(classLabels).transpose() #转换为numpy矩阵,并进行转置 59 m,n = np.shape(dataMatrix) #返回数组每一维的大小,m为行数,n为列数 60 alpha = 0.001 #步长即学习速率 61 maxCycles = 500 #最大迭代次数 62 weights = np.ones((n,1)) #构造n*1的元素全为1的矩阵 63 for k in range(maxCycles): #梯度上升公式 64 h = sigmoid(dataMatrix * weights) 65 error = labelMat - h 66 weights = weights + alpha * dataMatrix.transpose() * error 67 return weights 68 69 """ 70 随机梯度上升算法 71 相比于梯度上升算法,有两处改进的地方: 72 1.alpha在每次迭代更新是都会调整,这会缓解数据波动或者高频运动。此外,alpha还有一个常数项,目的是为了保证在多次迭代后仍然对新数据具有一定的影响,如果要处理的问题是动态变化的,可以适当加大该常数项,从而确保新的值获得更大的回归系数。 73 2.更新回归系数(最优参数)时,只使用一个样本点,并且选择的样本点是随机的,每次迭代不使用已经用过的样本点。这样的方法,就有效地减少了计算量,并保证了回归效果。 74 """ 75 def randomGradientAscent(dataMat,classLabels,numIter=150): #numIter为迭代次数默认为150 76 dataMatrix = np.array(dataMat) #将list或tuple变量转换成numpy的array数组 77 m,n = np.shape(dataMatrix) #返回数组每一维的大小,m为行数,n为列数 78 weights = np.ones(n) #构造1*n的元素全为1的矩阵 79 for j in range(numIter): 80 dataIndex = list(range(m)) #获取数据集行下标列表 81 for i in range(m): 82 alpha = 4/(1.0+i+j)+0.01 #每次更新参数时设置动态的步长,且为保证多次迭代后对新数据仍然具有一定影响 83 randIndex = int(random.uniform(0,len(dataIndex)))#随机选取样本 84 h = sigmoid(sum(dataMatrix[randIndex]*weights)) #选择随机选取的一个样本,计算h 85 error = classLabels[randIndex] - h #计算误差 86 weights= weights + alpha* error * dataMatrix[randIndex] #更新回归系数 87 del(dataIndex[randIndex]) #删除已经使用的样本 88 return weights 89 90 """ 91 梯度上升算法,绘制数据集和拟合直线 92 """ 93 def plotBestFit(weights): 94 dataMat,labelMat=loadDataSet() 95 dataArr = np.array(dataMat) #将list或tuple变量转换成numpy的array数组 96 n = np.shape(dataMat)[0] #numpy.shape返回数组每一维的大小 97 xcord1 = []; ycord1 = [] #正样本 98 xcord2 = []; ycord2 = [] #负样本 99 for i in range(n): #将样本集分类 100 if int(labelMat[i]) == 1: 101 xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) 102 else: 103 xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) 104 105 fig = plt.figure() 106 ax = fig.add_subplot(111) #添加subplot 107 ax.scatter(xcord1,ycord1,s = 20 , c='red', marker = 's',alpha=0.5) #绘制正样本 108 ax.scatter(xcord2,ycord2,s = 20 , c='green', alpha=0.5) #绘制负样本 109 110 x = np.arange(-3.0,3.0,0.1) 111 y = (-weights[0] -weights[1] * x) / weights[2] 112 ax.plot(x,y) 113 plt.title("DataSet") #绘制title 114 plt.xlabel('x1'); plt.ylabel('x2') #绘制label 115 plt.show() #显示 116 117 if __name__ == '__main__': 118 #plotDataSet() 119 dataMat,labelMat=loadDataSet() 120 #weights = gradientAscent(dataMat,labelMat).getA() #(梯度上升算法)将矩阵转换为数组,返回权重数组,不转化会报错 121 weights = randomGradientAscent(dataMat,labelMat) #(随机梯度上升算法) 122 plotBestFit(weights)
2.从疝气病症预测病马的死亡率
1 """ 2 使用随机梯度上升算法,解决病马死亡率问题 3 """ 4 import numpy as np 5 import random 6 7 def sigmoid(inX): 8 return 1.0/(1+np.exp(-inX)) 9 10 """ 11 随机梯度上升算法 12 相比于梯度上升算法,有两处改进的地方: 13 1.alpha在每次迭代更新是都会调整,这会缓解数据波动或者高频运动。此外,alpha还有一个常数项,目的是为了保证在多次迭代后仍然对新数据具有一定的影响,如果要处理的问题是动态变化的,可以适当加大该常数项,从而确保新的值获得更大的回归系数。 14 2.更新回归系数(最优参数)时,只使用一个样本点,并且选择的样本点是随机的,每次迭代不使用已经用过的样本点。这样的方法,就有效地减少了计算量,并保证了回归效果。 15 """ 16 def randomGradientAscent(dataMat,classLabels,numIter=150): #numIter为迭代次数默认为150 17 dataMatrix = np.array(dataMat) #将list或tuple变量转换成numpy的array数组 18 m,n = np.shape(dataMatrix) #返回数组每一维的大小,m为行数,n为列数 19 #print(m,n) 20 #print(len(classLabels)) 21 weights = np.ones(n) #构造1*n的元素全为1的矩阵 22 for j in range(numIter): 23 dataIndex = list(range(m)) #获取数据集行下标列表 24 for i in range(m): 25 alpha = 4/(1.0+i+j)+0.01 #每次更新参数时设置动态的步长,且为保证多次迭代后对新数据仍然具有一定影响 26 randIndex = int(random.uniform(0,len(dataIndex)))#随机选取样本 27 #print(i ,randIndex) 28 h = sigmoid(sum(dataMatrix[randIndex]*weights)) #选择随机选取的一个样本,计算h 29 error = classLabels[randIndex] - h #计算误差 30 weights= weights + alpha* error * dataMatrix[randIndex] #更新回归系数 31 del(dataIndex[randIndex]) #删除已经使用的样本 32 return weights 33 34 """ 35 分类函数,判断分类 36 """ 37 def classifyVector(inX , weights): 38 prob = sigmoid(sum(inX*weights)) 39 if prob>0.5: 40 return 1.0 41 else: 42 return 0.0 43 44 """ 45 测试分类器 46 """ 47 def colicTest(): 48 dataMat,labelMat = loadDataSet() 49 trainWeigths = randomGradientAscent(dataMat,labelMat,500) 50 frTest = open('horseColicTest.txt') 51 numTestVec =0.0 #测试样例总数 52 errorCount =0 #错误样例数 53 for line in frTest.readlines(): 54 numTestVec += 1.0 55 currArr = line.strip().split(' ') 56 lineArr = [] 57 for i in range(len(currArr)-1): 58 lineArr.append(float(currArr[i])) 59 if int(classifyVector(np.array(lineArr),trainWeigths)) != int(currArr[-1]): 60 errorCount += 1 61 errorRate = (float(errorCount)/numTestVec)*100 62 print("测试集错误率为:%.2f%%" %errorRate) 63 64 """ 65 加载数据 66 """ 67 def loadDataSet(): 68 dataSet = [] #数据列表 69 labelMat = [] #标签列表 70 frTrain = open('horseColicTraining.txt') 71 for line in frTrain.readlines(): 72 #print(line) 73 currArr = line.strip().split(' ') 74 lineArr = [] 75 for i in range(len(currArr)-1): 76 lineArr.append(float(currArr[i])) 77 dataSet.append(lineArr) 78 labelMat.append(float(currArr[-1])) #添加标签 79 frTrain.close() 80 return dataSet, labelMat 81 82 if __name__ == '__main__': 83 colicTest()
3.使用sklearn预测病马的死亡率
1 """ 2 使用sklearn构建逻辑回归分类器 3 """ 4 from sklearn.linear_model import LogisticRegression 5 """ 6 加载数据 7 """ 8 def loadDataSet(): 9 dataSet = [] #数据列表 10 labelMat = [] #标签列表 11 frTrain = open('horseColicTraining.txt') 12 for line in frTrain.readlines(): 13 #print(line) 14 currArr = line.strip().split(' ') 15 lineArr = [] 16 for i in range(len(currArr)-1): 17 lineArr.append(float(currArr[i])) 18 dataSet.append(lineArr) 19 labelMat.append(float(currArr[-1])) #添加标签 20 frTrain.close() 21 return dataSet, labelMat 22 23 24 """ 25 加载测试数据 26 """ 27 def loadTestDataSet(): 28 dataSet = [] #数据列表 29 labelMat = [] #标签列表 30 frTrain = open('horseColicTest.txt') 31 for line in frTrain.readlines(): 32 #print(line) 33 currArr = line.strip().split(' ') 34 lineArr = [] 35 for i in range(len(currArr)-1): 36 lineArr.append(float(currArr[i])) 37 dataSet.append(lineArr) 38 labelMat.append(float(currArr[-1])) #添加标签 39 frTrain.close() 40 return dataSet, labelMat 41 42 """ 43 测试分类器 44 """ 45 def colicTest(): 46 dataMat,labelMat = loadDataSet() 47 testMat,testLabelMat = loadTestDataSet() 48 classifier = LogisticRegression(solver ='liblinear',max_iter =10).fit(dataMat,labelMat) 49 accurcyRate = classifier.score(testMat,testLabelMat)*100 50 print("测试集正确率为:%.2f%%" %accurcyRate) 51 52 53 if __name__ == '__main__': 54 colicTest()