一、Logistic回归
使用一条直线对一些数据点进行拟合(该线称为最佳拟合线),这个拟合过程叫做回归。利用Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。训练Logistic分类器的做法就是寻找最佳拟合参数,使用的是最优化算法(梯度上升算法以及改进的随机梯度上升算法)。基于Python实现的完整Logistic代码连接:
https://download.csdn.net/download/pcb931126/10874534
二、基于Logistic回归和Sigmoid函数的分类
在Logistic回归中我们使用Sigmoid函数替代单位阶跃函数,进行运算。Sigmoid函数具体计算公式如下:
σ(z)=1+e−z1
下图给出了Sigmoid函数在不同坐标尺度下的两条曲线图。因此,为了实现Logistic回归分类器,我们可以在在每个特征上都乘以一个回归系数,然后把所有结果都相加,将总和带入到Sigmoid函数中,进而得到一个在0~1之间的数值。任何大于0.5的数据被分入1类,小于0.5的被归入0类。所以Logistic回归可以看做是一种概率估计。
三、基于最优方法的最佳回归系数的确定
Sigmoid函数的输入为
z,由下面的公式可以得出:
z=w0x0+w1x1+w2x2+...+wnxn
如果采用向量的写法,上述公式可以写成
z=wTx,它将表示将这两个数值向量对应元素相乘然后全部加起来得到
z值。其中的向量
x是分类器的输入数据,向量
w也就是我们要找到的最佳回归系数,从而使得分类器尽可能的精确。
3.1 梯度上升法
梯度上升法基于的思想是:找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。函数梯度上升的梯度算子总是指向函数值增长最快的方向,每一次移动一个步长
α ,到下一个点重新计算该点的梯度。因此梯度上升法的迭代公式如下:
w:=w+αΔwf(w))
该将公式将一直被迭代,直到达到某个停止条件为止,比如迭代次数达到某个指定值或者算达到某个可以允许的误差范围。
3.2 训练算法;使用梯度上升找到最佳参数
梯度上升的伪代码如下:
每个回归系数初始化为1
重复
R次:
计算整个数据集的梯度
使用
alpha∗gradient更新回归系数的向量
返回回归系数
基于python实现的代码如下
def gradAscent(dataMatIn,classLabels):
dataMatrix=mat(dataMatIn) #将数组转转成矩阵(100*3)
labelMat=mat(classLabels).transpose() #将行向量转置成列向量
m,n=shape(dataMatrix) #得到dataMatrix矩阵的行和列
alpha=0.001 #初始化回归系数,向目标移动的步长
maxCycles=500 #最大迭代次数
weights=ones((n,1)) #初始换权重系数,有多个特征向量,就会有多少个权重系数
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights) #矩阵对应位置相乘,将得到的值作为Sigmoid的输入,得到类别标签
error=(labelMat-h) #将得到的类别标签与真实的类别标签相减得到误差
weights=weights+alpha*dataMatrix.transpose()*error #权重更新
return weights
其分类结果使用mayplotlib画出分类边界以及原始数据分布如下图所示
3.3 改进算法:改进随机梯度上升法
梯度上升算法在每次更新回归系数时都需要遍历整个数据集,档处理商量数据集时尚可,当处理大数据集时该方法的复杂度就太高了。一种改进的随机梯度上升的方法是一次随机选择一个样本点来更新回归系数。由于可以在新的样本到来时对分类器进行增量式更新,因此随机梯度上升算法是一个在线学习算法。改进随机上升算法的伪代码如下所示:
每个回归系数初始化为1
随机选择数据集中的一个样本:
按照迭代次数调整步长
计算该样本的梯度
使用
alpha∗gradient更新回归系数的向量
删除该样本的索引
返回回归系数值
基于python实现的代码如下:
def stocGradAscent0(dataMatrix,classLabels,numIter=150):
m,n=shape(dataMatrix)
weightChange=[] #记录权重变换量
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 #alpha每次迭代时都会调整,这样就会缓解数据波动或者高频振动
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]) #将使用过的值从列表中删除,在进行下一次迭代
weightChange.append(weights)
return weights,weightChange
其分类结果使用mayplotlib画出分类边界以及原始数据分布如下图所示
从分类结果可以看出,改进算的随机上升梯度算法和梯度上升算法的分类效果基本相同,但是计算的复杂度大大降低,在计算大数据集的时候可以节省大量的时间。改进的随机梯度上升方法权值更新的变化如下图所示:
由权值变化可知,改进随机梯度上升算法的步长
alpha每次迭代都会调整,这回环节数据的波动或者高频波动。并且通过随机选择样本来更新回归系数,这将减少周期性波动。
四、Logistic完整的代码
"""
机器学习Logistic回归
姓名:pcb
时间:2018.12.24
"""
from numpy import *
import matplotlib.pyplot as plt
from numpy import exp
"""
加载待分类文本函数
"""
def loadDataSet():
dataMat=[];labelMat=[]
fr=open('testSet.txt')
for line in fr.readlines():
lineArr=line.strip().split() #指定分隔符对字符串进行切片
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
"""
Sigmoid函数实现
"""
def sigmoid(inX):
if inX>=0:
return 1.0/(1+exp(-inX))
else:
return exp(inX)/(1+exp(inX))
#--------Logistic回归梯度上升优化算法-----------------------------------------------
"""
Logistic回归梯度上升优化算法
"""
def gradAscent(dataMatIn,classLabels):
dataMatrix=mat(dataMatIn) #将数组转转成矩阵(100*3)
labelMat=mat(classLabels).transpose() #将行向量转置成列向量
m,n=shape(dataMatrix) #得到dataMatrix矩阵的行和列
alpha=0.001 #初始化回归系数,向目标移动的步长
maxCycles=500 #最大迭代次数
weights=ones((n,1)) #初始换权重系数,有多个特征向量,就会有多少个权重系数
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights) #矩阵对应位置相乘,将得到的值作为Sigmoid的输入,得到类别标签
error=(labelMat-h) #将得到的类别标签与真实的类别标签相减得到误差
weights=weights+alpha*dataMatrix.transpose()*error #权重更新
return weights
#------------------------------------------------------------------------------
#--------Logistic回归改进的随机梯度上升优化算法-----------------------------------------
#为了减少计算复杂度,一次随机选取一个样本点,使用这个一个样本点进行回归系数的更新
def stocGradAscent0(dataMatrix,classLabels,numIter=150):
m,n=shape(dataMatrix)
weightChange=[] #记录权重变换量
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 #alpha每次迭代时都会调整,这样就会缓解数据波动或者高频振动
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]) #将使用过的值从列表中删除,在进行下一次迭代
weightChange.append(weights)
return weights,weightChange
#------------------------------------------------------------------------------
#---------示例:从疝气病症预测病马死亡率------------------------------------------
"""
分类函数,以回归系数和特征向量作为输入来计算对应的Sigmoid函数值
"""
def classifyVector(inX,weights):
prob=sigmoid(sum(inX*weights))
if prob>0.5:
return 1.0
else:
return 0.0
"""
用于打开测试集和训练集,并对数据进行格式化处理的函数
"""
def coliTest():
frTrain = open('horseColicTraining.txt')
frTest = open('horseColicTest.txt')
trainingSet=[];trainingLabel=[]
for line in frTrain.readlines():
currLine=line.strip().split(' ')
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabel.append(float(currLine[21]))
trainsWeight,trianWeightChanges=stocGradAscent0(array(trainingSet),trainingLabel,500)
errorCount=0;numTestVec=0.0
for line in frTest.readlines():
numTestVec+=1.0
currLine1=line.strip().split(' ')
lineArr1=[]
for i in range(21):
lineArr1.append( float(currLine1[i]))
if int(classifyVector(array(lineArr1),trainsWeight))!=int(currLine1[21]):
errorCount+=1
errorRate=float(errorCount)/numTestVec
print('the error rate of this test is:%f'%errorRate)
return errorRate
def multiTest():
numTests=10;errorSum=0.0
for k in range(numTests):
errorSum+=coliTest()
print('after %d iteraTions the average error rate is: %f'%(numTests,errorSum/float(numTests)))
#-----------------------------------------------------------------------------
#--------画出数据集和Logistic回归最佳拟合直线的函数--------------------------------
"""
画出数据集和Logistic回归最佳拟合直线的函数
"""
def plotBestFit(weights):
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)
ax.scatter(xcord1,ycord1,s=30,c='red',marker='s')
ax.scatter(xcord2,ycord2,s=30,c='green')
x=arange(-3.0,3.0,0.1)
y=(-weights[0]-weights[1]*x)/weights[2]
ax.plot(x,y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.savefig('Logistic回归梯度上升优化算法.png')
plt.show()
#----------------------------------------------------------------------------
#-----------权重变量X0,X1,X2的变化图-------------------------------------------
def plotWeightChange(weightsChange):
input_value=range(0,4000)
m,n=shape(weightsChange)
X0=[];X1=[];X2=[]
for i in range(4000):
X0.append(weightsChange[i][0])
X1.append(weightsChange[i][1])
X2.append(weightsChange[i][2])
#第一张图,关于权重X0的变化情况
fig1=plt.figure(num=1,figsize=(10,10),dpi=400)
ax1 = fig1.add_subplot(3,1,1)
ax2 = fig1.add_subplot(3,1,2)
ax3 = fig1.add_subplot(3,1,3)
ax1.plot(input_value,X0)
ax1.set_ylabel('X0',fontsize=15)
ax1.set_xlim(0, 4000) # 设置横轴范围,单独给图1设置x轴的范围
ax1.set_ylim(-2, 14) # 设置横轴范围,单独给图1设置y轴的范围
#第二张图,关于X1的变化情况
ax2.plot(input_value,X1)
ax2.set_ylabel('X1',fontsize=15)
ax2.set_xlim(0, 4000) # 设置横轴范围,单独给图1设置x轴的范围
ax2.set_ylim(-3, 5) # 设置横轴范围,单独给图1设置y轴的范围
#第三张图,关于X2的变化情况
ax3.plot(input_value,X2)
ax3.set_ylabel('X2',fontsize=15)
ax3.set_xlim(0, 4000) # 设置横轴范围,单独给图1设置x轴的范围
ax3.set_ylim(-30, 10) # 设置横轴范围,单独给图1设置y轴的范围
plt.savefig('Logistic回归改进的随机梯度上升优化算法权重变化曲线图.png')
plt.show()
#----------------------------------------------------------------------------
def main():
# #1.-------对Logistic回归梯度上升优化算法测试并画出拟合曲线以及分类结果图-----------
# dataArr,labelMat=loadDataSet()
# weights,weightsChange=gradAscent(dataArr,labelMat)
# print(weights)
# plotBestFit(weights.getA()) #getA()函数与mat()函数的功能相反,是将一个numpy矩阵转换为数组
# #---------------------------------------------------------------------------
# #2.------Logistic回归随机梯度上升优化算法进行测试-------------------------------
# dataArr,labelMat=loadDataSet()
# weights1,weightsChange1=stocGradAscent0(array(dataArr),labelMat)
# plotWeightChange(weightsChange1)
# plotBestFit(weights1)
# #---------------------------------------------------------------------------
#3.--------示例:从疝气病症预测病马死亡率----------------------------------------
multiTest()
#----------------------------------------------------------------------------
if __name__=='__main__':
main()