机器学习笔记(6)-逻辑回归与最大熵模型

Logistic回归

Logistic 回归虽然名字叫回归,但是它是用来做分类的。其主要思想是: 根据现有数据对分类边界线建立回归公式,以此进行分类。假设现在有一些数据点,我们用一条直线对这些点进行拟合(这条直线称为最佳拟合直线),这个拟合的过程就叫做回归
Sigmoid 函数
Sigmoid 函数具体的计算公式
这里写图片描述

def sigmoid(inX):
    return 1.0/(1+exp(-inX))

为了实现 Logistic 回归分类器,我们可以在每个特征上都乘以一个回归系数(如下公式所示),然后把所有结果值相加,将这个总和代入 Sigmoid 函数中,进而得到一个范围在 0~1 之间的数值。任何大于 0.5 的数据被分入 1 类,小于 0.5 即被归入 0 类。所以, Logistic 回归也可以被看成是一种概率估计。
Sigmoid 函数的输入记为 z ,由下面公式得到:
这里写图片描述

逻辑斯蒂回归模型

1. 二项逻辑斯蒂回归模型
二项逻辑斯蒂回归模型是如下的条件概率分布:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
意义:在逻辑斯蒂回归模型中,输出Y=1的对数机率是输入x的线性函数。或者说,输出Y=1的对数机率是由属于x的线性函数表示的模型,即逻辑斯蒂回归模型。
感知机只通过决策函数(w⋅x)的符号来判断属于哪一类。逻辑斯蒂回归需要再进一步,它要找到分类概率P(Y=1)与输入向量x的直接关系,再通过比较概率值来判断类别。
令决策函数(w⋅x)输出值等于概率值比值取对数,即:
这里写图片描述
逻辑斯蒂回归模型的定义式P(Y=1|x)中可以将线性函数w⋅x转换为概率,这时,线性函数的值越接近正无穷,概率值就越接近1;线性函数的值越接近负无穷,概率值就接近0.
2. 模型参数估计
应用极大似然法进行参数估计,从而获得逻辑斯蒂回归模型。
这里写图片描述
这里写图片描述
上式连乘符号内的两项中,每个样本都只会取到两项中的某一项。若该样本的实际标签yi=1,取样本计算为1的概率值π(xi);若该样本的实际标签yi=0,取样本计算的为0的概率值1−π(xi)。
3对数似然函数为:
这里写图片描述
对上式中的L(w)求极大值,得到w的估计值。
问题转化成以对数似然函数为目标函数的无约束最优化问题,通常采用梯度下降法以及拟牛顿法求解w。
假设w的极大估计值是wˆ,那么学到的逻辑斯蒂回归模型为:
利用梯度上升找到最佳参数
这里写图片描述
这里写图片描述
4. 交叉熵损失函数的求导:逻辑回归的另一种理解是以交叉熵作为损失函数的目标最优化。交叉熵损失函数可以从上文最大似然推导出来。 交叉熵损失函数为:
这里写图片描述
则可以得到目标函数为:
这里写图片描述
计算J(θ)对第j个参数分量θj求偏导:
这里写图片描述

def gradAscent(dataMatIn, classLabels):
    '''正常的梯度上升法
    :param dataMatIn: ataMatIn 是一个2维NumPy数组,每列分别代表每个不同的特征,每行则代表每个训练样本。
    :param classLabels: classLabels 是类别标签,它是一个 1*100 的行向量。为了便于矩阵计算,需要将该行向量转换为列向量,做法是将原向量转置,再将它赋值给labelMat。
    :return array(weights)-得到的最佳回归系数
    '''
    dataMatrix = mat(dataMatIn)
    labelMat = mat(classLabels).transpose()  # 转化为矩阵[[0,1,0,1,0,1.....]],并转制[[0],[1],[0].....]
    m,n = shape(dataMatrix)
    alpha = 0.001     # alpha代表向目标移动的步长
    maxCycles = 500   # 迭代次数
    weights = ones((n,1))  # 生成一个长度和特征数相同的矩阵
    for k in range(maxCycles):
        h = sigmoid(dataMatrix*weights)     # mxn+nx1->mx1
        error = (labelMat - h)
        weights = weights + alpha * dataMatrix.transpose() * error # 矩阵乘法,最后得到回归系数
    return array(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
        print weights, "*"*10 , dataMatrix[i], "*"*10 , error
        weights = weights + alpha * error * dataMatrix[i]
    return weights

改进的随机梯度上升算法:1,alpha在每次迭代的时候都会调整;2,通过随机选取样本来更新回归系数;

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    '''
    :param dataMatrix: 输入数据的数据特征(除去最后一列数据)
    :param classLabels: 输入数据的类别标签(最后一列数据)
    :param numIter: 迭代次数
    :return: weights -- 得到的最佳回归系数
    '''
    m,n = shape(dataMatrix)
    weights = ones(n)   # 创建与列数相同的矩阵的系数矩阵,所有的元素都是1
    for j in range(numIter):  # 随机梯度, 循环150,观察是否收敛
        dataIndex = range(m)
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001    # alpha 会随着迭代不断减小,但永远不会减小到0,因为后边还有一个常数项0.0001
            randIndex = int(random.uniform(0,len(dataIndex)))  # random.uniform(x, y) 方法将随机生成下一个实数,它在[x,y]范围内,x是这个范围内的最小值,y是这个范围内的最大值。
            h = sigmoid(sum(dataMatrix[randIndex]*weights))  # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

根据权重用logistic画最佳拟合直线

def plotBestFit(dataArr, labelMat, weights):
    '''将我们得到的数据可视化展示出来
    :param dataArr: 样本数据的特征
    :param labelMat: 样本数据的类别标签,即目标变量
    :param weights: 回归系数
    :return: 
    '''
    n = shape(dataArr)[0]
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, 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('X'); plt.ylabel('Y')
    plt.show()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章