对数几率回归-Logistic Regression

本文深入探讨了Logistic Regression(对数几率回归)的基本概念及其数学原理,包括几率与对数几率的概念、Sigmoid函数的作用及意义,并详细推导了对数似然函数和损失函数的形成过程。

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

Logistic Regression是一个经典的判别学习分类方法。参考资料—西瓜书&&机器学习公开课-Andrew Ng。
首先我们来看为什么Logistic Regression被称为对数几率回归。

几率:将一个实例映射到正例或者负例的可能性比率。令P(y=1|x;θ)P(y=1|x;θ)表示将样本分类成正例的概率。那么P(y=0|x;θ)=1P(y=1|x;θ)P(y=0|x;θ)=1−P(y=1|x;θ)就表示将样本分类成负例的概率。那么这里的几率表示为:
P(y=1|x;θ)1P(y=1|x;θ)P(y=1|x;θ)1−P(y=1|x;θ)

对数几率:对数几率就是对上式求对数。

回归就是线性回归方法。因此:对数几率回归的表达式如下:
logP(y=1|x;θ)1P(y=1|x;θ)=θTxlogP(y=1|x;θ)1−P(y=1|x;θ)=θTx
经过简单的代数运算,我们得到
P(y=1|x;θ)=eθTx1+eθTxP(y=1|x;θ)=eθTx1+eθTx;以及
P(y=0|x;θ)=11+eθTxP(y=0|x;θ)=11+eθTx

我们看到P(y=1|x;θ)P(y=1|x;θ)P(y=0|x;θ)P(y=0|x;θ)的表达式实际上就是Sigmoid函数。那么为什么要这样做呢?

通过线性回归的方法做分类,理想的情况下是这样来做:

z=θTxz=θTx,当z<0,样本被分类成负例;当z>0,样本被分类成正例;当z=0,样本可以任意分类。显然,这里预测函数为单位阶跃函数

y=hθ(x)=g(z)=0.1,z>0,5,z=0,0,z<0(33)(33)y=hθ(x)=g(z)={1,z>0,0.5,z=0,0,z<0

g(z)的函数图像如下图红线所示:
这里写图片描述
而单位阶跃函数是不连续不可微的,这对于我们求解参数带来了很大的不便。
因此,科学家们就想到用另外一个连续可微函数近似替代这个阶跃函数。常用的替代函数如上图黑线所示,它也被称为Sigmoid函数,也可以被称为对数几率函数。同样地,当对数几率函数值大于0.5,样本被分类成正例;小于0.5,样本被分类成负例;等于0.5,样本可被任意分类。

上面就是对对数几率函数的一些解释。咱们继续,在得到了P(y=1|x;θ)P(y=1|x;θ)P(y=0|x;θ)P(y=0|x;θ)之后,我们得到后验概率如下,对某一个训练样本:

P(yi|xi;θ)=yiP(yi=1|xi;θ)+(1yi)P(yi=0|xi;θ)P(yi|xi;θ)=yiP(yi=1|xi;θ)+(1−yi)P(yi=0|xi;θ)

写出对数似然函数:
L(θ)=logni=1P(yi|xi;θ)=ni=1logP(yi|xi;θ)L(θ)=log∏i=1nP(yi|xi;θ)=∑i=1nlogP(yi|xi;θ)

诶 忽然发现有些不对,
logP(yi|xi;θ)=log[yiP(yi=1|xi;θ)+(1yi)P(yi=0|xi;θ)]logP(yi|xi;θ)=log[yiP(yi=1|xi;θ)+(1−yi)P(yi=0|xi;θ)]不好处理。于是,我们改写:
P(yi|xi;θ)P(yi|xi;θ)
=yiP(yi=1|xi;θ)+(1yi)P(yi=0|xi;θ)=yiP(yi=1|xi;θ)+(1−yi)P(yi=0|xi;θ)
=P(yi=1|xi;θ)yiP(yi=0|xi;θ)1yi=P(yi=1|xi;θ)yiP(yi=0|xi;θ)1−yi
于是,
L(θ)=ni=1[yilogP(yi=1|xi;θ)+(1yi)logP(yi=0|xi;θ)]L(θ)=∑i=1n[yilogP(yi=1|xi;θ)+(1−yi)logP(yi=0|xi;θ)]
=ni=1[yilogeθTxi1+eθTxi+(1yi)log11+eθTxi]=∑i=1n[yilogeθTxi1+eθTxi+(1−yi)log11+eθTxi]
=ni=1[yi(θTxilog(1+eθTxi))(1yi)log(1+eθTxi)]=∑i=1n[yi(θTxi−log(1+eθTxi))−(1−yi)log(1+eθTxi)]
=ni=1[yiθTxilog(1+eθTxi)]=∑i=1n[yiθTxi−log(1+eθTxi)]
极大化对数似然等价于极小化其负数

minθL(θ)=ni=1[yiθTxi+log(1+eθTxi)]=L̂ (θ)minθ−L(θ)=∑i=1n[−yiθTxi+log(1+eθTxi)]=L^(θ)

从损失函数的角度也可以导出上述式子

定义损失函数

Cost(hθ(x),y)={log(hθ(x)),y=1,log(1hθ(x)),y=0.(34)(34)Cost(hθ(x),y)={−log(hθ(x)),y=1,−log(1−hθ(x)),y=0.

化简得到 Cost(hθ(x),y)=log[(hθ(x))y(1hθ(x))1y]Cost(hθ(x),y)=−log[(hθ(x))y(1−hθ(x))1−y]
训练数据总体损失
J(θ)=ni=1Cost(hθ(xi),yi)=ni=1[yiloghθ(xi)+(1yi)log(1hθ(xi))]=L̂ (θ)J(θ)=∑i=1nCost(hθ(xi),yi)=−∑i=1n[yiloghθ(xi)+(1−yi)log(1−hθ(xi))]=L^(θ)

最终目标为
minθJ(θ)minθJ(θ)
目标函数对θθ求偏导可得
θJ(θ)=ni=1[yixi+xieθTxi1+eθTxi]∂∂θJ(θ)=∑i=1n[−yixi+xieθTxi1+eθTxi]
这个式子的解析解不容易给出,于是利用标准梯度下降法给出θθ的迭代公式如下:

θ(j+1):=θ(j)αθJ(θ(j))θ(j+1):=θ(j)−α∂∂θJ(θ(j))

当然,也可以通过牛顿法,随机梯度下降等其他经典的方法求解。

下面附上代码(Python实现),建议在PyCharm下运行,数据集采用的是《机器学习实战》的Logistic回归测试数据:

# -*- coding:utf-8 -*-
# This class is built for logistic regression
__author__ = 'yanxue'

import numpy as np
from numpy import random
from numpy import linalg
from matplotlib import pyplot as plt
import math

class LogisticRegression:
    def __init__(self):
        pass

    def learning(self, data, label, learning_rate=0.1, convergence_rate=1):
        """Learning process of the logistic regression"""
        n, d = data.shape
        self.theta = random.randn(d + 1)
        theta0 = random.randn(d + 1)
        count = 0
        c_error = 0
        for j, x in enumerate(data):
            pLabel = lr.classify(x)
            c_error += pLabel != label[j]
        yield c_error, theta0
        ind = 0
        while linalg.norm(theta0 - self.theta) > convergence_rate:
            print('theta_{} = {}'.format(count, theta0))
            self.theta = theta0.copy()
            # gradient decent
            theta0 -= learning_rate * sum(map(self.__fun, [(data[i], label[i]) for i in range(n)]))
            # Stochastic gradient descent
            # theta0 -= learning_rate * self.__fun((data[ind % n], label[ind % n]))
            # ind += 1
            # Batch gradient descent
            # theta0 -= learning_rate * sum(map(self.__fun, [(data[i % n], label[i % n]) for i in range(ind, ind + 10)]))
            # ind += 10
            c_error = 0
            for j, x in enumerate(data):
                pLabel = lr.classify(x)
                c_error += pLabel != label[j]
            yield c_error, self.theta
            count += 1

    def __fun(self, trainx):
        return -trainx[1] * np.append(trainx[0], 1) + np.append(trainx[0], 1) * self.s(trainx[0])

    def classify(self, x):
        if self.s(x) < 0.5:
            return 0
        elif self.s(x) >= 0.5:
            return 1

    def s(self, inx):
        """Sigmoid function value"""
        try:
            re = 1 / (1 + math.exp(-np.dot(self.theta, np.append(inx, 1))))
        except OverflowError as e:
            print(e)
            re = 1
        return re

    def __str__(self):
        return "Logistic regression"

trainData = np.loadtxt('data/LogisticRegressionTestSet.txt', delimiter='\t')
trainX = trainData[:, [0, 1]]
trainY = trainData[:, 2]
lr = LogisticRegression()
# ------ Plot the data points ------
x1 = np.arange(-4.0, 3.2, 0.1)
plt.close()
plt.ion()  #interactive mode on
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
# ------ End of plot ------
for c_error, c_theta in lr.learning(trainX, trainY):
    # ------ Plot the iterative process ------
    plt.grid()
    plt.scatter(trainX[trainY == 0, 0], trainX[trainY == 0, 1], c='r')  # plot positive instances
    plt.scatter(trainX[trainY == 1, 0], trainX[trainY == 1, 1], c='b')  # plot negative instances
    plt.xlabel('$x_1$')
    plt.ylabel('$x_2$')
    plt.title('Logistic Regression Demo')
    x2 = (-c_theta[0] * x1 - c_theta[2]) / c_theta[1]
    plt.plot(x1, x2)
    plt.text(-4, 12.5, 'errorNum = {}'.format(c_error))
    # ------ End of plot ------
    plt.pause(0.2)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值