1. 逻辑回归是干什么的?

逻辑回归是一种用来解决分类问题的算法。比如:

  • 判断一封邮件是垃圾邮件还是正常邮件

  • 判断一张图片是还是

  • 判断一个学生是否能通过考试(通过 or 不通过)。

它的目标是找到一个“分界线”,把不同的类别分开。比如下图:

复制

🐱 🐱 🐱 🐱 🐈 | 🐶 🐶 🐶 🐶

这条竖线就是逻辑回归找到的“分界线”,左边是猫,右边是狗。


2. 逻辑回归是怎么工作的?

逻辑回归的核心思想是:根据输入的数据,计算出一个概率值,然后根据概率值判断属于哪一类

举个例子:

假设我们要判断一个学生是否能通过考试,输入数据是学生的学习时间,输出是通过(1)不通过(0)

  • 如果学习时间越长,通过的概率越大。

  • 如果学习时间越短,通过的概率越小。

逻辑回归的任务就是找到一个公式,把学习时间映射到通过的概率上。


3.原理

 (1) 逻辑回归的“魔法公式”

        逻辑回归的核心是一个叫Sigmoid函数的魔法公式,它可以把任意数值变成一个0到1之间的概率值。公式长这样:

P(y=1)=\frac{1}{1+e^{-z}}

其中:

        

举个例子:

假设我们有一个简单的逻辑回归模型:

  • 输入特征:学习时间 x 。

  • 权重:ω  = 2。

  • 偏置:b = −10。

那么公式就是:

        z = 2x - 10

        P(y=1) = \frac{1}{1 + e^{-(2x - 10)}}

  • 如果学习时间 x=6小时:

    •  z = 2 \times 6 - 10 = 2

    • P(y=1) = \frac{1}{1 + e^{-2}} \approx 0.88

  • 也就是说,通过考试的概率是88%!

(2)逻辑回归的预测规则

        根据概率值 P(y=1),我们可以进行分类预测:

        

(3)损失函数

        逻辑回归的训练目标是找到最优的权重 ω 和偏置 b,使得预测结果尽量接近真实值。这里使用的损失函数是 交叉熵损失函数

        J(\mathbf{w}, b) = -\frac{1}{m} \sum_{i=1}^{m} \left[ y^{(i)}\log\left(P(y^{(i)}=1)\right) + (1 - y^{(i)})\log\left(1 - P(y^{(i)}=1)\right) \right]

        m 样本数量;y^{(i)}是第 i 个样本的真实标签;P(y^{(i)}=1)是模型预测的概率。

(5)梯度下降更新公式

        通过梯度下降法,我们可以更新权重 ω 和偏置 b:

        w_j := w_j - \alpha \frac{\partial J(\mathbf{w}, b)}{\partial w_j}

b := b - \alpha \frac{\partial J(\mathbf{w}, b)}{\partial b}

        α是学习率;\alpha \frac{\partial J(\mathbf{w}, b)}{\partial w_j}\alpha \frac{\partial J(\mathbf{w}, b)}{\partial b}分别是损失函数对 w_j  和 b 的偏导数。


4. 逻辑回归的训练

逻辑回归的模型需要通过学习数据来找到最好的权重 ω 和偏置 b。这个过程叫做训练

  • 训练的目标是让模型的预测结果和真实结果尽量接近。

  • 通过不断调整 ω 和 b,模型会变得越来越准。


5. python代码

import numpy as np
from sklearn.model_selection import train_test_split

# 定义Sigmoid函数,用于将线性输出转换为概率输出
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

# 预测函数,根据输入特征X和模型参数w, b,输出预测结果
def predict(X, w, b):
    z = np.dot(X, w) + b  # 计算线性输出
    y_pred = sigmoid(z)  # 将线性输出转换为概率输出
    # 将概率转换为类别(0或1),通常设定一个阈值如0.5
    y_pred = np.where(y_pred >= 0.5, 1, 0)
    return y_pred

# 损失函数(交叉熵损失),用于评估模型性能
def compute_loss(y_true, y_pred):
    m = y_true.shape[0]  # 样本数量
    # 为了避免log(0)的情况,我们在y_pred和1-y_pred中添加了一个很小的数1e-9
    loss = -1/m * np.sum(y_true * np.log(y_pred + 1e-9) + (1 - y_true) * np.log(1 - y_pred + 1e-9))
    return loss

# 梯度下降更新规则,用于优化模型参数
def gradient_descent(X, y_true, w, b, learning_rate, num_iterations):
    m = X.shape[0]  # 样本数量
    for i in range(num_iterations):  # 迭代优化
        z = np.dot(X, w) + b  # 计算线性输出
        y_pred = sigmoid(z)  # 计算预测概率
        # 计算梯度
        dw = np.dot(X.T, (y_pred - y_true)) / m
        db = np.sum(y_pred - y_true) / m
        # 更新模型参数
        w -= learning_rate * dw
        b -= learning_rate * db
        # 每100次迭代打印一次损失值,用于监控训练过程
        if i % 100 == 0:
            loss = compute_loss(y_true, predict(X, w, b))
            print(f"Iteration {i}: Loss = {loss}")
    return w, b

# 示例数据:学生的数学和英语成绩,以及是否通过了考试(1表示通过,0表示未通过)
# 数据格式:[数学成绩, 英语成绩, 是否通过考试]
data = [
    [90, 85, 1],  # 学生1:数学90,英语85,通过考试
    [78, 74, 0],  # 学生2:数学78,英语74,未通过考试
    [88, 92, 1],  # 学生3:数学88,英语92,通过考试
    [65, 70, 0],  # 学生4:数学65,英语70,未通过考试
    [85, 80, 1],  # 学生5:数学85,英语80,通过考试
    [50, 60, 0],  # 学生6:数学50,英语60,未通过考试
    [78, 72, 1],  # 学生7:数学78,英语72,通过考试
    [90, 65, 1],  # 学生8:数学90,英语65,通过考试
    [62, 58, 0],  # 学生9:数学62,英语58,未通过考试
    [88, 92, 1],  # 学生10:数学88,英语92,通过考试
    [55, 45, 0],  # 学生11:数学55,英语45,未通过考试
    [70, 85, 1],  # 学生12:数学70,英语85,通过考试
    [48, 52, 0],  # 学生13:数学48,英语52,未通过考试
    [95, 80, 1],  # 学生14:数学95,英语80,通过考试
    [68, 76, 1],  # 学生15:数学68,英语76,通过考试
    [52, 64, 0],  # 学生16:数学52,英语64,未通过考试
    [82, 79, 1],  # 学生17:数学82,英语79,通过考试
    [40, 50, 0],  # 学生18:数学40,英语50,未通过考试
    [75, 65, 1],  # 学生19:数学75,英语65,通过考试
    [60, 80, 1],  # 学生20:数学60,英语80,通过考试
    [50, 50, 0]   # 学生21:数学50,英语50,未通过考试
]

# 分离特征和标签
X = np.array([d[:2] for d in data])  # 特征:数学和英语成绩
y_true = np.array([d[2] for d in data]).reshape(-1, 1)  # 标签:是否通过考试

# 将数据集划分为训练集和测试集(80%训练,20%测试)
X_train, X_test, y_train, y_test = train_test_split(X, y_true, test_size=0.2, random_state=42)

# 添加偏置项(将X的第一列设置为1),这样我们就可以在矩阵乘法中同时考虑权重和偏置
X_train_b = np.c_[np.ones((X_train.shape[0], 1)), X_train]
X_test_b = np.c_[np.ones((X_test.shape[0], 1)), X_test]

# 初始化权重和偏置,使用小的随机数进行初始化
np.random.seed(42)  # 为了结果可复现
w = np.random.randn(X_train_b.shape[1], 1) * 0.01
b = 0

# 超参数设置
learning_rate = 0.1  # 学习率,控制参数更新的步长
num_iterations = 1000  # 迭代次数,控制训练过程的轮数

# 训练模型,通过梯度下降优化模型参数
w, b = gradient_descent(X_train_b, y_train, w, b, learning_rate, num_iterations)

# 使用训练好的模型进行预测
y_train_pred = predict(X_train_b, w, b)
y_test_pred = predict(X_test_b, w, b)

# 输出训练集和测试集的预测结果
print("训练集预测:", y_train_pred.flatten())
print("测试集预测:", y_test_pred.flatten())

# 输出结果解释,将预测结果和真实标签进行对比
print("\n训练集结果:")
for i, (pred, true) in enumerate(zip(y_train_pred.flatten(), y_train.flatten())):
    print(f"学生 {i+1}: 预测 {'Pass' if pred == 1 else 'Fail'}, 实际 {'Pass' if true == 1 else 'Fail'}")

print("\n测试集结果:")
for i, (pred, true) in enumerate(zip(y_test_pred.flatten(), y_test.flatten())):
    print(f"学生 {i+1}: 预测 {'Pass' if pred == 1 else 'Fail'}, 实际 {'Pass' if true == 1 else 'Fail'}")
#运行结果展示;我们这里的数据集比较少,只是为了说明这个例子。实际中数据集体量很大。
Iteration 0: Loss = 6.476020573358253
Iteration 100: Loss = 6.476020573358253
Iteration 200: Loss = 11.656837032844855
Iteration 300: Loss = 6.476020573358253
Iteration 400: Loss = 6.476020573358253
Iteration 500: Loss = 14.247245262588155
Iteration 600: Loss = 6.476020573358253
Iteration 700: Loss = 6.476020573358253
Iteration 800: Loss = 14.247245262588157
Iteration 900: Loss = 7.771224688229903
训练集预测: [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
测试集预测: [0 0 0 0 0]

训练集结果:
学生 1: 预测 Fail, 实际 Fail
学生 2: 预测 Fail, 实际 Pass
学生 3: 预测 Fail, 实际 Fail
学生 4: 预测 Fail, 实际 Pass
学生 5: 预测 Fail, 实际 Pass
学生 6: 预测 Fail, 实际 Pass
学生 7: 预测 Fail, 实际 Pass
学生 8: 预测 Fail, 实际 Pass
学生 9: 预测 Fail, 实际 Fail
学生 10: 预测 Fail, 实际 Pass
学生 11: 预测 Fail, 实际 Fail
学生 12: 预测 Pass, 实际 Pass
学生 13: 预测 Fail, 实际 Fail
学生 14: 预测 Fail, 实际 Pass
学生 15: 预测 Fail, 实际 Pass
学生 16: 预测 Fail, 实际 Pass

测试集结果:
学生 1: 预测 Fail, 实际 Pass
学生 2: 预测 Fail, 实际 Fail
学生 3: 预测 Fail, 实际 Fail
学生 4: 预测 Fail, 实际 Fail
学生 5: 预测 Fail, 实际 Fail

6. 总结

  • 逻辑回归是一种分类算法,用来预测概率。

  • 它通过Sigmoid函数把输入映射到0到1之间的概率值。

  • 训练过程是调整权重和偏置,让模型更准。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐