首先看看梯度上升算法:
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn)
labelMat = np.mat(classLabels).transpose()
m, n = np.shape(dataMatrix)
alpha = 0.001
maxCycles = 500
weights = np.ones((n, 1))
for i in range(maxCycles):
h = sigmoid(dataMatrix * weights)
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error
return weights
再看看改进的随机梯度上升算法:
def stocGradAscent1(dataMatrix, classLabels, numInter=150):
m, n = np.shape(dataMatrix)
weights = np.ones(n)
for j in range(numInter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4 / (1.0 + j + i) + 0.01
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
《机器学习实战》书中原话:
梯度上升算法在每次更新回归系数是都需要遍历整个数据集,该方法在处理100个左右的数据集尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度就太高了。一种改进方法是一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法。
然后在网上看到如下问题:
问题一: 改进的随机梯度上升算法的内层循环次数是100,该算法还是把数据集中的每个样本都遍历了一遍,那么这和之前的梯度上升算法有什么区别?
我们注意到:
梯度上升算法遍历一次数据集时只对回归系数进行了一次修改,而改进的随机梯度上升算法对数据集遍历一次时,因为每选择一个样本点,就对回归系数进行了一次修改,遍历完整个数据集其实对回归系数修改了100次!
问题二:
randIndex通过randIndex=int(random.uniform(0, len(dataIndex)))得到 [0,100)之间的一个整数,假设randIndex=10,那么del(dataIndex[randIndex])之后len(dataIndex)就变为99了。第二次循环时randIndex在区间[0,99)中随机取一个整数,万一刚好又取到randIndex=10,则又要用该样本点来修改回归系数。试想一种极端的情况:randIn一直取到10,难道要一直用这一个样本点来修改参数吗,其他样本点没起到一点作用,这显然不合理啊!
Too Naive!还是Python语法学的不够牢固啊!
我们先来看看下面这段代码,熟悉熟悉del函数的功能
motorcycles=['honda','yamaha','toyota','suzuki']
del(motorcycles[1])
print(motorcycles)
输出 [‘honda’, ‘toyota’, ‘suzuki’]
del()函数直接删除列表中对应下标的元素
再看看下面这个代码,你就一目了然了,根本不是问题二所说的那么回事!
import random
a = list(range(10))
for i in range(10):
print('------------------------')
print(a)
randIndex = int(random.uniform(0, len(a)))
print(randIndex)
del(a[randIndex])
print(a)
输出的结果如下:
------------------------
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9
[0, 1, 2, 3, 4, 5, 6, 7, 8]
------------------------
[0, 1, 2, 3, 4, 5, 6, 7, 8]
7
[0, 1, 2, 3, 4, 5, 6, 8]
------------------------
[0, 1, 2, 3, 4, 5, 6, 8]
3
[0, 1, 2, 4, 5, 6, 8]
------------------------
[0, 1, 2, 4, 5, 6, 8]
3
[0, 1, 2, 5, 6, 8]
------------------------
[0, 1, 2, 5, 6, 8]
3
[0, 1, 2, 6, 8]
------------------------
[0, 1, 2, 6, 8]
1
[0, 2, 6, 8]
------------------------
[0, 2, 6, 8]
3
[0, 2, 6]
------------------------
[0, 2, 6]
0
[2, 6]
------------------------
[2, 6]
0
[6]
------------------------
[6]
0
[]
看到没,删除相应下标的元素,该元素就从列表中移除了。观察输出结果的第10行到第20行,虽然randIndex都是3,但对应的列表元素已经换了!分别是3,4,5。所以即使randIndex取到相同的值,但绝不是相同的样本了。