机器学习实战(四)--逻辑斯特回归

来源:互联网 发布:淘宝账号购买记录查询 编辑:程序博客网 时间:2024/04/29 21:33

一.sigmoid函数

1.函数思想

当我们想生成一个函数,通过这个函数我们给定特征值,就能预测输出。对二分类问题,很容易我们会想到阶跃函数(函数输出0或1)。但这种阶跃性很多时候处理起来都是困难的,自然地,我们想要一个平滑过渡版的阶跃函数。这种数学上更易于处理的过渡更平滑的函数就是sigmoid函数。

2.函数形式

可以看到下面那张图已经非常接近阶跃函数了,只不过中间的过渡是平滑的。

二.分类问题

1.基本思想

对于给定的特征x1,x2...xn,令

(可以用向量符号表示成z=wTx的形式)。

对利用二分类问题,利用sigmiod函数求值,函数值大于0.5判定为A类,小于0.5则判定为B类。其实,我们可以将函数值看成一个概率估计。

那么,该分类问题的重点就在于如何确定各个特征的系数(权重)。

2.最优化算法

1)梯度上升

梯度上升的基本思想是:如果我们想找函数的最大值,那么最好是朝着梯度方向(梯度永远指向上升最快的方向)移动。

但是该思想仅仅指出了移动的方向,但是并没有提及移动的幅度(也就是步长)。我们用α来表示步长,那么 梯度上升算法可以用向量符号表示成如下形式:

很明显该算法还需要一个停止条件,停止条件可以是一个给定的步数,或是一个确定的容忍范围。

这样就得到了梯度上升算法的三大要素:移动方向,移动步长和停止条件。伪代码如下:

具体代码实现:

from numpy import *def loadDataSet():    dataMat = []; labelMat = []    fr = open('testSet.txt')    for line in fr.readlines():        lineArr = line.strip().split()        # input feature => two dimension        # 1.0 stands for (w1x1+w2x2+..w0)'s w0        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])        labelMat.append(int(lineArr[2]))    return dataMat, labelMatdef sigmoid(inX):    return 1.0/(1+exp(-inX))def gradAscent(dataMatIn, classLabels):    # dataMatrix => 100x3 matrix(2 features+ 0th feature, 100 training data)    dataMatrix = mat(dataMatIn)    # labelMat => column vector    labelMat = mat(classLabels).transpose()    # m=> num of training data, n => num of features + 1    m, n = shape(dataMatrix)    # the step size    alpha = 0.001    # maxCycles => num of times u'r going to repeat the calculation before stopping    maxCycles = 500    # initialize all the coefficient as 1    weights = ones((n,1))    for k in range(maxCycles):        # h => a column vector ,len=m, h(estimated value for each training data)        h = sigmoid(dataMatrix*weights)        # estimated error        error = (labelMat - h)        # optimization target will be introduced later        weights = weights + alpha*dataMatrix.transpose()*error    return weights

2)随机梯度上升

梯度上升存在的一个问题就是计算复杂度太高-----梯度上升算法每次迭代更新的时候都使用了整个数据集,这对小数据集来说可能是ok的,但是对大量数据来说计算代价太高昂了。一个可选的解决办法就是每次更新权重的时候只使用一个实例。这就是著名的随机梯度下降。

随机梯度上升是一种在线学习算法,因为它可以在每次新数据到来时完成参数更新,而不需要重新读取整个数据集来进行批处理。伪代码如下:

在代码上,基本的随机梯度上升跟梯度上升算法的唯一差别就在于随机梯度上升每次只取一个样本点,代码如下:

def stocGradAscent0(dataMatrix, classLabels):    m, n = shape(dataMatrix)    alpha = 0.01    weights = ones(n)    for i in range(m):        # now h is a single value, not vector(same for error)        h = sigmoid(sum(dataMatrix[i]*weights))        error = classLabels[i] -h        weights = weights + alpha*error*dataMatrix[i]    return weights
由于两个最优化算法的迭代次数不同,直接比较是不公平的。一个判断优化算法优劣的可靠方法是看它是否收敛。本数据集使用随机梯度上升的收敛情况如下:

由上面的(迭代次数---权重值)可以看到,x0、x1经历了很多次迭代才达到稳定,同时每个权重都存在不同程度的震荡。

由此,优化的随机梯度上升算法在以下两方面做了改进:

1)alpha是动态递减而非常量,其实可以理解成在迭代过程中不断接近极值,这时候我们需要缩小步长,以免步长过大跨过极值;

2)真正随机的去选取每次用于更新权重的样本(避免上图所示的周期性波动)。


3. 最大似然估计

看了上面的优化,你会发现我们还并没有讲到优化目标。逻辑斯特回归中一般使用最大似然估计来对特征系数进行估计。

因为各个观测样本之间相互独立,那么它们的联合分布为边缘分布的乘积。那么对全体样本而言,优化目标就是求出使如下所示似然函数最大化的参数:



简单来说,最大似然估计的意义就在于寻找一组,对现有训练样本匹配度最高的,参数。

有了优化目标,我们就可以使用梯度上升的方法来求最优参数了。一般地,我们使用对数似然函数最大化来方便求解。


对上述似然函数求偏导,得到

所以根据梯度上升法有:

但是细心的同学又会发现一个问题了,参数wk没有初始化呀!根据经验一般初始化为全零,全1,或者随机值。值得注意的是初始值会影响最后的结果,不合适的初始值可能会导致最后求得的是极大值,而非最大值。


4.算法理解

详见统计学习方法<x>逻辑斯特回归。to be continued...








0 0