机器学习实战——Logistic回归

本文详述了Logistic回归的理解过程,包括目标描述、代价函数、梯度下降法及其向量表示,重点解析Sigmoid函数在二分类问题中的作用。通过实例展示了100个样本点的Logistic回归训练、测试与应用,同时提及了梯度上升与随机梯度下降的优化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天看《机器学习实战》里面的logistic回归篇,发现里面虽然内容不多,但是作者省略了很多过程,结果自己看得有点懵,后来查了一些资料,然后自己推了推公式,才有了豁然开朗的感觉。这里就记录一下自己的理解,也希望和大家一起分享。

Github: 梯度下降


数学部分

—————————————————————————————————————————————————————————————

1.目标描述

之前我们说过一个物体可以抽象成许多特征的集合,在这里我们用X表示物体:


其中表示特征,表示每个特征的权重,用一个大家都在用的例子解释就是:就好比房子的价格,而就是影响房价的各个因素(房屋面积,房屋朝向,房屋所在地段等),同时则是每个影响因素的权重,这些所有的影响因素(特征)共同决定了房价。


2.代价函数

既然我们已经确定了目标描述的方法,那么该取什么值,才能最好最贴切地描述物体本身呢?(一般房屋所在地段及房屋面积对房价影响较大,所以其对应的就会大一些

为了求解,我们需要个样本(),这里的个样本是已经知道真实值的(即属于已经分好类的)

这里我们需要构建一个代价函数(构建的方法有很多,这里我们用最小二乘法):


其中表示第i个样本,表示第i个样本的真实描述值。

当我们使最小时,也就是我们估计得到的与真实的总误差最小时,即可认为我们选取的是最合适的!


3.梯度下降

现在我们的目标是使得代价函数最小,即求:


对了,这个时候我们的梯度就出场了:


注:梯度指示了该如何变化(即变化的方向),才能使得最小。

对于每一个的偏导数均可以表示为:


其中表示第i个样本,表示第i个样本的真实描述值,表示第i个样本的第j个特征。

好了,到了这里接下来就容易多了,要确保最小,那么就应该这么变化:


其中表示每次迭代的步长(即每次变化的幅度),而则指示了每次变化的方向。当所有收敛到某一个值的时候,此时最小。


4.向量表示法

①梯度下降向量描述:



②对于每一个的偏导数向量描述:



其中


5. Sigmoid函数

这个函数主要用来归一化处理用的,对于像二分类这样的问题(结果只有0和1),我们将的值归一化到0或1,这样更有利于我们分类。



100个样本点的logistic回归

—————————————————————————————————————————————————————————————

#准备数据:这里使用书本里面已经格式化好的数据

#训练算法:利用已有数据,使用梯度下降法寻找最优回归系数

#测试算法:可以采用交叉验证

#使用算法:利用最优回归系数构建的分类器进行样本分类

注:《机器学习实战》里面用的是梯度上升,其实和梯度下降的结果是一致的。用上升还是下降,其实与构造函数的凹凸性有关,不用特别在意,毕竟函数都是自己构造的,你可以保证它的凹凸性。程序里面除了常规的梯度下降法,还包含了随机梯度下降法,这是一种更加高效的求解最优解的方法。

# -*- coding: UTF-8 -*-
import numpy as np
from matplotlib import pyplot as plt

def drawSigmod():
    plt.figure()
    plt.subplot(111)

    X = np.linspace(-60, 60, 256, endpoint=True)
    Y = 1 / (1 + np.exp(-X))

    plt.plot(X, Y)

    plt.ylim(Y.min() - 0.1, Y.max() * 1.1)

    plt.show()

def sigmod(inX):
    return 1.0 / (1 + np.exp(-inX))

def loadDataSet(path):
    # Set: X0 = 1.0
    dataSet = []; labelSet = []
    with open(path, 'r') as f:
        for line in f.xreadlines():
            lineArr = line.strip().split()
            dataSet.append([1.0, float(lineArr[0]), float(lineArr[1])])
            labelSet.append(float(lineArr[2]))
    return dataSet, labelSet

def gradDescend(trainMatIn, trainLabelIn):
    trainMat = np.mat(trainMatIn)
    trainLabel = np.mat(trainLabelIn).transpose()

    alpha = 0.001 # alpha为步长
    m, n = np.shape(trainMat) # m为样本数量,n为特征个数
    loopCount = 500 # 迭代次数
    theta = np.ones((n, 1)) # 初始化回归系数

    for i in xrange(loopCount):
        h = sigmod(trainMat * theta)
        error = h - trainLabel
        theta  -= alpha * trainMat.transpose() * error
    return theta

def randGradDescend(trainMatIn, trainLabelIn):
    import random

    trainMat = np.array(trainMatIn) # list转换为numpy.array
    trainLabel = np.array(trainLabelIn)

    alpha = 0.01 # 初始化步长
    m, n = np.shape(trainMat) # m个样本,n个特征
    theta = np.ones(n) # 初始化回归系数
    loopCount = 40 # 迭代次数

    for j in xrange(loopCount):
        for i in xrange(m):
            alpha += 4 / (1 + i + j)
            randIndex = int(random.uniform(0, m))
            h = sigmod(sum(theta * trainMat[randIndex]))
            error = h - trainLabel[randIndex]
            theta -= alpha * error * trainMat[randIndex]
    return theta


def main():
    data, label = loadDataSet("testSet.txt")
    theta = gradDescend(data, label)
    thetaRand = randGradDescend(data, label)
    dataArr = np.array(data)
    m, n = np.shape(dataArr)
    print m, n
    print len(label)
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    for i in xrange(m):
        if label[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=50, c='red')
    ax.scatter(xcord2, ycord2, s=50, c='blue')
    x = np.arange(-3.0, 3.0, 0.1)
    y1 = (- theta[0] - theta[1] * x) / theta[2]
    y2 = (- thetaRand[0] - thetaRand[1] * x) / thetaRand[2]
    ax.plot(x, y1, c='green')
    ax.plot(x, y2, c= 'green')
    plt.xlabel('x1'); plt.ylabel('x2')
    plt.show()



if __name__ == "__main__":
    main()





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值