Logistic回归之梯度上升优化算法(三)
1、改进的随机梯度上升算法
前面两节讲了Logistic回归以及里面常用的梯度上升优化算法来找到最佳回归系数。但是梯度上升优化算法的计算量很大,每次更新回归系数时都需要遍历整个数据集。下面给出之前所讲的梯度上升算法:
def gradAscent(dataMatIn, classLables):
dataMatrix = np.mat(dataMatIn) #转换成numpy的mat
# print(dataMatrix)
labelMat = np.mat(classLables).transpose() #转换成numpy的mat,并进行转置
# print(labelMat)
m, n =np.shape(dataMatrix)#返回dataMatrix的大小。m为行,n为列
alpha = 0.001 #移动补偿,也就是学习速率,控制更新的幅度
maxCycles = 500 #最大迭代次数
weights = np.ones((n,1))
# print(weights)
for k in range(maxCycles):
h = sigmoid(dataMatrix *weights) #梯度上升矢量公式
# print(h)
error = labelMat - h
weights = weights + alpha * dataMatrix.transpose()*error
return weights.getA() #将矩阵转换为数组,返回权重数组
该算法在对一个100个样本的数据集处理时,dataMatrix是一个100*3的矩阵,每次计算h的时候,都要计算dataMatrix*weights这个矩阵乘法运算,要进行100*3次乘法运算和100*2次加法运算。在更新weights时也需要对整个数据集进行处理,对于大样本是不可取的,为此使用一种随机梯度上升算法来简化算法。
1.1、随机梯度上升算法
我们直接给出代码:
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = np.shape(dataMatrix) #返回dataMatrix的大小 m为行数 n为列数
weights = np.ones(n) #[1. 1. 1.] 初始化参数 类型是array所以注意dataMatrix类型也应该是np.array
for j in range(numIter):
dataIndex = list(range(m)) # [0,1,...99]
for i in range(m):
alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次减小1/(j+i)
randIndex = int(random.uniform(0,len(dataIndex)))#随机选取样本
h = sigmoid(sum(dataMatrix[randIndex]*weights))#选择随机选取的一个样本,计算h。对应位置相乘求和
error = classLabels[randIndex] - h
weights = weights+ alpha* error*dataMatrix[randIndex]#更新回归系数
del(dataIndex[randIndex])#删除已经使用的样本
return weights
该算法主要是在以下两方面做了改进。第一,alpha在每次迭代的时候都会调整,随着迭代次数不断减小,但永远不会减小到0。这样做的原因是为了保证在多次迭代之后新数据仍然具有一定的影响。如果要处理的问题是动态变化的,那么可以适当加大上述常数项,来确保新的值获得更大的回归系数。而且在降低alpha的函数中,alpha每次减少1/(j+i),其中j是迭代次数,i是样本的下标。这样当j<<max(i)时,alpha就不是严格下降的。避免参数的严格下降也常见于模拟退火算法等其他优化算法中。第二,这里通过每次随机选取一个样本来更新回归系数。这种方法可以有效的减少周期性的波动。
代码如下:
import matplotlib.pyplot as plt
import numpy as np
import random
from matplotlib.font_manager import FontProperties
'