【机器学习实战】Logistic回归(二)

回顾

Logistic回归(一)中最后提到的Logistic回归核心代码如下:

def gradAscent(dataMatIn,classLabels):
    dataMatrix = mat(dataMatIn)
    labelMat = mat(classLabels).transpose()
    m,n = shape(dataMatrix)
    alpha = 0.001
    maxCycles = 500
    weights = ones((n,1))
    for k in range(maxCycles):
        h = sigmoid(dataMatrix*weights)
        error = labelMat - h
        weights = weights + alpha * dataMatrix.transpose() * error
    return weights

优化


思路

  从中可以发现,每一次迭代都会对所有样本进行计算,也就是说每一次运算量 = 特征数样本数。当样本数或特征较多的时候,计算量会十分巨大,这时候就会尝试去减少每一次参与运算的样本数,肯定不能减少特征。这就是作者想要说的随机梯度上升算法。


这里作者提到了两个概念

在线学习算法:在新样本到来的时候对分类器进行增量式更新,随机梯度上升算法就属于这一类
批处理算法:一次性处理所有数据

第一次优化

def stocGradAscent0(dataMatrix,classLabels):
    m,n = shape(dataMatrix)
    alpha = 0.01
    weights = ones(n)
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i] * weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights

分析

 这个算法比较简单明了,仅仅是按顺序将每一个样本带入计算了一次。由于梯度下降需要大量样本不断重复强化某一个特征的属性,该特征的参数才会逐渐收敛,所以很明显这样结果不会很理想的。


第二次优化


书中程序:

def stocGradAscent1(dataMatrix,classLabels,numIter = 150):
    m,n = shape(dataMatrix)
    weights = ones(n)
    for j in range(numIter):
        dataIndex = range(m)
         for i in range(m):
        alpha = 0.1/(1.0 + j + i) 
        randIndex = int(random.uniform(0,len(dataIndex)))
        # randIndex = random.choice(dataIndex)
        h = sigmoid(sum(dataMatrix[randIndex] * weights))
        error = classLabels[randIndex] - h
        weights = weights + alpha * error * dataMatrix[randIndex]
        del(dataIndex[randIndex])
    return weights

由于作者是用的是python2,而我用的是python3,所以其中会有一些不兼容的地方,之后会做出改动。
分析
 比较启发人的一点是:步长不是一个定值,而是一个不断减小的值,我们都知道,随着代价函数的优化,当距离最优解比较近的时候,原来的步长会限制进一步靠近最优解,这时候只能靠限制迭代次数来结束程序,但是这样也有可能在后面的迭代过程中并没有得到优化,而步长是一个变值便解决了这一问题。
但是在这个里面,我不太懂:

for j in range(numIter):

按这个来说,反映的是迭代的变化,

for i in range(m):

那呢?意思是说每一次迭代运算次?
 先不说python3中无法使用的问题,每次是要把样本全部遍历一次的!这个不会把样本全部删除吗?这个随机生成便没有意义了呀?每一次迭代必然会把所有样本遍历一次,这样的话和未优化版本的区别只在于那个是矩阵运算,这个才分开来,这样效率反而会更低吧?

 我实在搞不懂这个地方,再加上版本不兼容问题,自己改进了一下,企图改进这个问题,程序如下:

def stocGradAscent1(dataMatrix,classLabels,numIter = 50):
    m,n = shape(dataMatrix)
    weights = ones(n)
    dataIndex = list(range(m))
    for j in range(numIter):
        alpha = 0.1/(1.0 + j ) 
        rand = int(random.uniform(0,len(dataIndex)))
        randIndex = dataIndex.pop(rand)
        #测试代码
        # if dataIndex:
        #  randIndex = dataIndex.pop(rand)
        # else:
        #     print("The list is empty {}".format(j))
        # randIndex = random.choice(dataIndex)
        h = sigmoid(sum(dataMatrix[randIndex] * weights))
        error = classLabels[randIndex] - h
        weights = weights + alpha * error * dataMatrix[randIndex]
    return weights

思路
 我把转换成List进行运算,每次随机出一个随机数,这样也会满足功能需要。除此之外,改为单个循环结构进行循环,没有什么可说的,仅仅是按我的理解写的这个随机梯度上升(下降)而已。

至于作者最后写的实际的例子,便先不做分析,因为只是利用python在进行数据处理,主要是看编程的熟练度了

你可能感兴趣的:(【机器学习实战】Logistic回归(二))