书中重要定义及一些理解

  • 先通过介绍逻辑史蒂的分布来引出logist模型
  • 而通过极大似然法来推导模型的参数估计问题
  • 通过对模型参数的似然函数通过求导来得到递归方程
  • 通过公式可以看出logist是对前面的感知机的升级版,感知机的判断方式过于简单。而其梯度下降的时候也将sign的去掉了,否则无法微分。
  • 后通过方程来写出公式,代码如下

 

import numpy as np
from read_data import get_2_kind_data


def logistic_Regression(tra_x, tra_y, lambdas=0.01, iter=200):
    '''
    逻辑斯蒂回归训练过程
    :param trainDataList:训练集
    :param trainLabelList: 标签集
    :param iter: 迭代次数
    :return: 习得的w
    '''
    # 按照书本“6.1.2 二项逻辑斯蒂回归模型”中式6.5的规则,将w与b合在一起,
    # 此时x也需要添加一维,数值为1
    tra_x = np.insert(tra_x, len(tra_x[0]), 1, 1)
    w = np.random.rand(len(tra_x[0]))
    for i in range(iter):  # 每次迭代冲遍历一次所有样本,进行随机梯度下降
        for j in range(len(tra_x)):
            # 随机梯度上升部分
            # 在“6.1.3 模型参数估计”一章中给出了似然函数,我们需要极大化似然函数
            # 但是似然函数由于有求和项,并不能直接对w求导得出最优w,所以针对似然函数求和
            # 部分中每一项进行单独地求导w,得到针对该样本的梯度,并进行梯度上升(因为是
            # 要求似然函数的极大值,所以是梯度上升,如果是极小值就梯度下降。梯度上升是
            # 加号,下降是减号)
            # 求和式中每一项单独对w求导结果为:xi * yi - (exp(w * xi) * xi) / (1 + exp(w * xi))
            # 如果对于该求导式有疑问可查看我的博客 www.pkudodo.com
            # 计算w * xi,因为后式中要计算两次该值,为了节约时间这里提前算出
            # 其实也可直接算出exp(wx),为了读者能看得方便一点就这么写了,包括yi和xi都提前列出了
            wx = np.dot(w, tra_x[j].T)
            yi = tra_y[j]
            xi = tra_x[j]
            w += lambdas * (xi * yi - (np.exp(wx) * xi) / (1 + np.exp(wx)))
    return w

def predict(w, x):
    '''
    预测标签
    :param w:训练过程中学到的w
    :param x: 要预测的样本
    :return: 预测结果
    '''
    #dot为两个向量的点积操作,计算得到w * x
    wx = np.dot(w, x)
    #计算标签为1的概率
    #该公式参考“6.1.2 二项逻辑斯蒂回归模型”中的式6.5
    P1 = np.exp(wx) / (1 + np.exp(wx))
    #如果为1的概率大于0.5,返回1
    if P1 >= 0.5:
        return 1
    #否则返回0
    return 0

def test(testDataList, testLabelList, w):
    '''
    验证
    :param testDataList:测试集
    :param testLabelList: 测试集标签
    :param w: 训练过程中学到的w
    :return: 正确率
    '''
    #与训练过程一致,先将所有的样本添加一维,值为1,理由请查看训练函数
    testDataList=np.insert(testDataList,len(testDataList[0]),1,1)
    #错误值计数
    errorCnt = 0
    #对于测试集中每一个测试样本进行验证
    for i in range(len(testDataList)):
        #如果标记与预测不一致,错误值加1
        if testLabelList[i] != predict(w, testDataList[i]):
            errorCnt += 1
    #返回准确率
    return 1 - errorCnt / len(testDataList)


if __name__ == '__main__':
    tra_x, test_x, tra_y, test_y = get_2_kind_data('data/Mnist/mnist_train.csv')
    tra_x, test_x = tra_x / 255, test_x / 255
    w=logistic_Regression(tra_x, tra_y)
    acc=test(test_x,test_y,w)
    print(acc)