Logistic回归(1)

什么是回归?

假设现在有一些数据点,我们用一条直线对这些点进行拟合(该线称为最佳拟合直线),这个拟合过程就称作回归。

 

涉及到回归问题,我们借助Sigmoid函数来处理,Sigmoid函数

x=0时,函数值是0.5x越大函数值越趋近于1x越小函数值越趋近于0

如果x的刻度足够大Sigmoid函数也可以堪称一个单位阶跃函数。之所以采用Sigmoid来解决回归问题,是因为在一定条件下Sigmoid函数呈现出“线性”的特性,“线性”的体现就是回归系数。

先来解释Sigmoid的线性,Sigmoid函数的输入记为z,假设有n个特性,也就是说有n个向量,那么Sigmoid函数中入参z可以标识成:

小写的w是各个向量上的回归系数,小写的x是各个向量上的入参。

如果采用向量的写法,上述公式可以写成z = WX,大写的W是多向量的回归系数,大写的X是多向量的一套入参。

从公式中我们可以看出只要W是非零值,Z最终都会趋于无穷大和无穷小,所以Sigmoid函数值终将趋于01;但是如果W足够小,那么X在一定范围内对Z的影响将会放缓,相当于将上面第一张图向X轴两边拉长了,那么在一定范围内就会趋向与一条直线,也就是说会变成线性的。例如W=0.1时,x(-7,7)之间的图形是这样的:

理解了线性之后后面的问题就变得简单了,我们对多向量的数据集进行01分组时就演化成了了求Z的过程,也就是求多向量的回归系数W的过程了。

 

在求得W的过程中采用的是梯度上升算法,梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为,则函数f(x,y)的梯度表示为:

梯度上升算法到达每个点后都会重新估计移动的方向。从P0开始,计算完该点的梯度,函数就根据梯度移动到下一点P1。在P1点,梯度再次被重新计算,并沿新的梯度方向移动到P2。如此循环迭代,直到满足停止条件。迭代的过程中,梯度算子总是保证我们能选取到最佳的移动方向

梯度上升算法,每上升一步,梯度算子总是指向函数值增长最快的方向,这里用的是方向而不是移动量的大小,是因为需要引入一个“步长”α的概念,步长越长,每次向山顶移动的越快,但是精准度越低,α的平衡是个学问。

梯度上升就是个不断递归的过程,每移动一步,更新当前的结果,重新计算剩下的最优方向,用公式标识是:

PS:梯度上升法如爬山一样,是求山顶最大值的方法,与梯度上升法对应的是梯度下降法,是求最小值的方法,将公式中的+号改成-号既可。


 

有了上面的理论基础,我们开始用代码和样例来演练下,训练文件在git上https://github.com/yejingtao/forblog/blob/master/MachineLearning/trainingSet/testSet.txt,格式如下:

-0.017612	14.053064	0

-1.395634	4.662541	1

-0.752157	6.538620	0

-1.322371	7.152853	0

0.423363	11.054677	0

0.406704	7.067335	1

0.667394	12.741452	0

其中前两项为特性,最后一列为结果。

要做的事情简单来说就是绘制一条“直线”,将图中这些训练集划分为两部分,处理这种01分类的场景我们采用前面介绍的Sigmoid函数,而求“直线”的过程就是求W的过程。

 

准备演示的训练集和结果集:

#加载训练集和结果集
def loadDataSet() :
    dataMat = []
    labelMat = []
    fr = open('C:\\2017\\提高\\机器学习\\训练样本\\testSet.txt')
    for line in fr.readlines():
        lineArray = line.strip().split()
        #这里给第一向量设置了1.0值,因为从分布图中看得出不是过原点的直线,所以要最终的W中要有x位的偏移量
        dataMat.append([1.0,float(lineArray[0]), float(lineArray[1])])
        labelMat.append(int(lineArray[2]))
    return dataMat,labelMat

#sigmoid函数
def sigmoid(inX) :
    return 1.0/(1.0+exp(-inX))


#最终返回的weights可以理解为梯度的塔顶
def gradAscent(dataMatIn, classLabels) :
    dataMatrix = mat(dataMatIn)
    #transpose将行数组转成列向量
    labelMatrix = mat(classLabels).transpose()
    m,n = shape(dataMatrix)
    # 返回的是步长alpha,训练次数maxCycle的回归系数
    alpha = 0.001
    maxCycle = 500
    weights = ones((n,1))
    for i in range(maxCycle) :
        #h是一个列向量
        h = sigmoid(dataMatrix * weights)
        #列向量相减,得到的还是个列向量error
        error = labelMatrix - h
        #dataMatrix.transpose()*error是矩阵相乘,事实上该运算包含了300次的乘积
        #梯度上升,对weights做修正
        weights = weights+alpha * dataMatrix.transpose()*error
    #返回也是个列向量
    return weights

利用matplotlib模块用图像来验证回归系数:

def plotBestFit(wei) :
    import matplotlib.pyplot as plt
    weights = wei.getA()
    dataMat, labelMat = loadDataSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    xc1=[]
    yc1=[]
    xc2=[]
    yc2=[]
    for i in range(n) :
        if int(labelMat[i])==1 :
            xc1.append(dataArr[i,1])
            yc1.append(dataArr[i,2])
        else :
            xc2.append(dataArr[i, 1])
            yc2.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xc1,yc1,s=30,c='red',marker='s')
    ax.scatter(xc2, yc2, 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.show()

测试代码:

dataMat,labelMat = loadDataSet()
weights = gradAscent(dataMat,labelMat)
print(weights)
plotBestFit(weights)

这里有一行代码不容易理解需要解释下:y = (-weights[0]-weights[1]*x)/weights[2],来自:

公式中x0=常量1x1=这里的xx2=这里的y,同时z0,是因为在z=0Sigmoid函数值为1/2正好是01的临界点。

所以从0= weights[0]*1+ weights[1]*x + weights[2]*y推导而来。

从图像结果来看回归系数比较理想,但是缺点也很明显,尽管例子简单且数据集很小,这个方法却需要大量的计算量。

假设我们的数据集是几万几亿 的话,该训练算法计算量将不可控制

再介绍下随机梯度上升法:

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

测试结果是:[ 1.01702007  0.85914348 -0.36579921]



一个判断优化算法优劣的可靠方法是看它是否收敛,也就是说参数是否达到了稳定值,是否还会不断地变化。可以看到目前结果并没有收敛,假如继续不断对随机梯度进行递归的话,最终将会收敛,这里请看下机器学习实践中给出的测试结果:


X0X1要迭代很久才能收敛,X2很快就可以收敛,X1X2存在一定的波动,波动来源于趋于临界点的数据,在n次修订后在n+1次又被修订回去,重复数据的来回修订引起了波动。


基于以上的分析我们对随机梯度上升法进行加强,第一如何最快收敛,第二如何减少波动。


1调整步长尽快收敛,开始时步长设置较大,减少前期计算上的浪费,越是趋于收敛时步长越小

2随机数据减少波动,前面已经分析过既然重复数据的来回修订引起了波动,那么我们就采用随机数据来训练算法。

 

加强后的代码是:

def stocGradAscent1 (dataMatrix, classLabels, numIter=150) :
    m,n = shape(dataMatrix)
    weights = ones(n)
    for j in range(numIter) :
        dataIndex = list(range(m))
        for i in range(m) :
            #动态的步长,i,j越大越趋于稳定,步长越小
            alpha = 4/(1.0+i+j) + 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

测试结果:

[ 14.56523388  0.87521806 -1.92639734]

虽然回归系数不如基本梯度上升法优秀,但是该算法是考虑到了计算量和回归性的平衡。


 

Logistic回归 

优点:计算代价不高,易于理解和实现。

缺点:容易欠拟合,分类精度可能不高。

适用数据类型:数值型和标称型数据。


PS:本文中的代码和训练数据来自机器学习实践





  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值