九哥使用的开发语言为Python3.5,不同版本请自动调整版本之间的用法差异。
本demo为九哥学习过程中的一个实例,训练数据和测试数据请自备。
###Logistic回归梯度上升算法
#conding:utf-8
from numpy import *
import math
import matplotlib.pyplot as plt
###导入数据
def loadDataSet():
dataMat = []
labelMat = []
fr = open(r'D:*****testSet.txt') #打开本地文件
for line in fr.readlines(): #逐行读取文本中的数据
lineArr = line.strip().split() #将文本中的每行的字符一个个分开,变成list。strip() 方法用于移除字符串头尾指定的字符(默认为空格)。
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])]) #将读取的数据列表的前2个字段添加到列表dataMat,为了好计算在dataMat列表中添加值1.0
labelMat.append(int(lineArr[2])) #将读取数据的第三个字段赋值给列表labelMat
return dataMat,labelMat
###定义sigmoid函数
def sigmoid(inX):
return 1.0/(1+exp(-inX))
###梯度上升方法求出回归系数
def gradAscent(data,label):
dataMat = mat(data) #将获取的数据转换为numpy矩阵类型
labelMat = mat(label).transpose() #将行向量转变为列向量
m,n = shape(dataMat) #返回dataMat矩阵向量的纬数(m),和行数(n)
alpha = 0.001 #设置移动步长
maxCycles = 500 #设置迭代次数
weights = ones((n,1)) #生成一个n行1列全由数字1组成的数组,初始回归系数
for item in range(maxCycles): #迭代500次训练回归系数
h = sigmoid(dataMat * weights) #预测每个样本的类别,h是一个列向量,向量元素等于样本个数
error = (labelMat - h) #计算真实类别与预测类别的差值,labelMat元素数据类型应是int
weights = weights + alpha * dataMat.transpose() * error #乘以误差值和步长,更新系数
return weights
测试:
data,label =logRegres.loadDataSet()
logRegres.plotBestFit(logRegres.gradAscent(data,label).getA())
####画出数据集和Logistic回归最佳拟合直线的函数
def plotBestFit(weights):
import matplotlib.pyplot as plt #导入Matplotlib画图工具
dataMat,labelMat = loadDataSet()
dataArr = array(dataMat) #将列表转为数组
n = shape(dataArr)[0] #获取样本的行数
xcode1 = []
ycode1 = []
xcode2 = []
ycode2 = []
for i in range(n):
if int(labelMat[i]) == 1: #遍历所有样本,分别抽取i样本类别为1和0的x,y坐标
xcode1.append(dataArr[i,1])
ycode1.append(dataArr[i,2])
else:
xcode2.append(dataArr[i,1])
ycode2.append(dataArr[i,2])
fig = plt.figure() #建图
ax = fig.add_subplot(111) #111表示画一行一列的第一幅图
ax.scatter(xcode1,ycode1,s = 30,c = 'red',marker = 's')
ax.scatter(xcode2,ycode2,s = 30,c = 'green')
x = arange(-3.0,3.0,0.1) #x线的范围,-3到3之间,间隔为0.1
###画出直线,weights[0]*1.0+weights[1]*x+weights[2]*y=0
###之前计算时对原始数据做了拓展,将2维拓展为三维,第一位全部设置为1.0
y = (-weights[0] - weights[1] * x) / weights[2]
ax.plot(x,y)
plt.xlabel('x1')
plt.ylabel('y1')
plt.show()
测试:
data,label = loadDataSet()weights = gradAscent(data,label)plotBestFit(weights.getA())
###梯度上升优化
def stocGradAscent1(dataMatrix,classLabels,numIter=150):
m,n = shape(dataMatrix) #返回参数dataMatrix向量参数的纬数(m)和行数(n)
weights = ones(n) #生成一个n行全由数字1组成的数组,初始回归系数
for j in range(numIter): #遍历150次
dataIndex = list(range(m)) #原因是python3中range不返回数组对象,而是返回range对象,所以range前加list转变类型
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #遍历优化步长,每次迭代时调整。j是迭代次数,i是样本点的下标
randIndex = int(random.uniform(0,len(dataIndex))) #随机选取一个0到dataIndex长度之间的实数
h = sigmoid(sum(dataMatrix[randIndex]*weights)) #通过sigmoid算法预测每个样本的类别,h是一个列向量,向量元素等于样本个数
error = classLabels[randIndex] - h ##计算真实类别与预测类别的差值
weights = weights + alpha * error * dataMatrix[randIndex] #乘以误差值和步长,更新系数
del(dataIndex[randIndex]) #删除dataIndex集合的下标第randIndex个元素
return weights
###贷款用户Logistic回归分类函数
def classifyVector(inx,weights):
prob = sigmoid(sum(inx*weights)) #将测试集上每个特征向量乘以最优化方法得来回归系数,再将乘积结果求和,输入到sigmoid函数中
if prob > 0.5 : return 1.0
else : return 0.0
###打开训练集和测试集,对数据进行格式化处理
def BorrowerTest():
frTrain = open(r'D:Machine LearningmachinelearninginactionCh05horseColicTraining.txt') #打开训练集
frTest = open(r'D:Machine LearningmachinelearninginactionCh05horseColicTest.txt') #打开测试集
trainingSet = [] #建立训练原数据集合
trainingLabels = [] #建立类别标签集合
for line in frTrain.readlines(): #逐行读取训练集中的数据
currLine = line.strip().split('') #每行数据按制表符分割
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i])) #将每行的24个特征数据添加到集合,range(24)下标0-24,但是不包含24
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[21])) #将每行样本数据的类别加入到类别集合
trainWeights = stocGradAscent1(array(trainingSet),trainingLabels,1000) #计算回归系数
errorCount = 0
numTestVec = 0
for line in frTest.readlines():
numTestVec += 1.0 #记录行数
currLine = line.strip().split('')
lineArr = []
for i in range(21):
lineArr.append(float(currLine[i]))
#计算回归系数与测试数据原类别是否相等
if int(classifyVector(array(lineArr), trainWeights)) != int(currLine[21]):
errorCount += 1
print('类别:',int(classifyVector(array(lineArr), trainWeights)))
errorRate = (float(errorCount)/numTestVec) #计算误差值
print('错误率是:',errorRate)
return errorRate
###调用BorrowerTest()函数并求10次结果的平均值
def multiTest():
numTests = 10
errorSum = 0.0
for k in range(numTests):
errorSum += BorrowerTest()
print('平均错误率是:', (numTests,errorSum/float(numTests)))
下一期九哥将会附上学习决策树的思路和代码。