机器学习之逻辑斯蒂回归及其python实现

写在前面

本文主要是学习记录贴,参考《统计学习方法》和部分博客完成。如有错误,欢迎积极评论指出。

初步了解

1 回顾

在前面感知机模型那一章,我们通过一个超平面,对所有的样本点进行分类,即样本点在超平面的哪一边,就将该样本点所属的类进行输出。
在这里插入图片描述
如上图所示,感知机模型中的sign是一个不光滑的函数,x=0是跳跃间断点,因此,无法进行微分。但是根据我们之前的了解,机器学习中,主要采用的是梯度下降的方式。而在感知机模型中,因为sign没办法微分,所以感知机模型对sign的内部,也就是w和b进行了梯度下降。而逻辑斯蒂回归,基于上面的思考,提出了一种新的解决方案。

2 问题与解决

首先,在感知机模型中,我们验证了sign(wx+b)的作用。但是在超平面附近的点,相隔距离很近的点,但是输出却差别很大。这个在我们实际感受中,显得有点怪。因此我们需要将这一点进行优化,使模型更贴近我们的现实感知。
结合之前讲过的朴素贝叶斯的概念,我们不一样非要输出其所属类别,我们可以该样本点属于+1和-1的概率,在根据概率值进行判断。这样,我们在超平面附近的点,不仅可以知道它所属的类别,还可以知道它属于这个类的一个可信度。
其次针对第二个问题,对于感知机模型的sign,是不可微的。虽然说我们可以跳过sign实现梯度下降。但是如果存在一个可微分函数,对sign进行替代,那么整个模型是不是就更加合理。

3 逻辑斯蒂回归

针对上面的解决方案,逻辑斯蒂回归模型被提出。对于感知机模型{-1,+1}的硬输出,逻辑斯蒂回归采用P(Y=1|x)和P(Y=0|x)代替输出。然后比较两个条件概率值的大小,将实例x分到概率值较大的类。
接下来是,逻辑斯蒂分布。
在这里插入图片描述
在这里插入图片描述
如上图所示,f(x)函数是平滑的,当x=0的时候,f(x)=0.5,当x接近于0的时候,概率值在0.5左右,表示对这个样本的分类没有太大把握。当x趋向于无穷大时,表示概率值为1或0,表示我们很确认这个分类结果是对的。

逻辑斯蒂回归二分类模型

逻辑斯蒂回归模型:
在这里插入图片描述
统计学习方法中,对w和b做了如下变换:
在这里插入图片描述
接下来,对似然函数进行求导:
在这里插入图片描述
接下来,我们就可以根据梯度上升或者梯度下降算法,对w进行学习。

逻辑斯蒂回归多分类

逻辑斯蒂回归多分类模型,是在二分类的基础上,实现的。多分类模型为:
在这里插入图片描述
其实原理很简单,对于多分类模型,其随机变量的取值范围为{1, 2, 3 …K},我们将取值范围分为两个部分,即{1, 2, 3…K-1}和{K},这样,又化为了二分类模型,接着循环,得到最终的分类结果。
这种多分类方式,用的其实已经不多了,因为softmax回归模型被提出后,逐渐取代了逻辑斯蒂多分类模型。接下来,我们来看看softmax回归模型。

softmax回归模型

公式推导如下:
在这里插入图片描述

代码实现

逻辑斯蒂回归相对简单,这里以softmax回归为例:

# The acc is:  0.9185

import numpy as np

# 导入数据
def LoadData(filename):
    data = []
    label = []
    file = open(filename)
    for line in file.readlines():
        curline = line.strip().split(',')
        data.append([int(int(dt) > 128) for dt in curline[1:]])   #二值化
        label.append(int(curline[0]))
    return data, label

#这段代码,传入的是一个数组,传出也是一个数组
def softmax(wx):
    return np.exp(wx) / np.sum(np.exp(wx))


# trainData:训练数据
# trainLabel:训练标签
# iter:迭代次数
# alpha:学习速率
def softmaxRegression(trainData, trainLabel, iter=200, alpha=0.001):
    for i in trainData:
        i.append(1)                     #根据书上,对特征末尾加上1,方便和[w,b]构成的数组进行内积运算
    trainData = np.array(trainData)
    k = 10                              # 分类数目
    w = np.zeros((k, len(trainData[0])))# 权重w,定义为10*785维数组
    for iter in range(iter):            
        print('迭代次数:', iter)        
        for j in range(len(trainData)): # 每一次迭代都遍历一次数据集
            x = trainData[j].reshape(-1, 1) # 转化为列向量
            y = np.zeros((10, 1))
            y[trainLabel[j]] = 1            # 当y==k时,输出1,否则为0。标签向量[0,0,0...k...K]
            y_i = softmax(np.dot(w, x))     
            w += alpha*(np.dot((y - y_i), x.T))     # 根据公式定义
    return w


def test(w, testData, testLabel):
    for data in testData:
        data.append(1)
    error = 0
    testData = np.array(testData)
    for i in range(len(testData)):
        predict = np.argmax(np.dot(w, testData[i].reshape(-1, 1)))   # 输出概率最大的值,即为预测结果
        if predict != testLabel[i]:
            error += 1
    return 1 - error/len(testData)


if __name__ == "__main__":   
    print('read train data')
    trainData, trainLabel = LoadData('Mnist/mnist_train/mnist_train.csv')

    print('read test data')
    testData, testLabel = LoadData('Mnist/mnist_test/mnist_test.csv')

    print('start calculate w')
    w = softmaxRegression(trainData, trainLabel)

    print('start test')
    acc = test(w, testData, testLabel)

    print('The acc is: ', acc)
  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值