← 返回信息流

dev.to #ai短讯

逻辑回归简介

dev.to作者:Abhishek Sharma教程AI评分:50/100

文章介绍了机器学习入门算法逻辑回归。指出线性回归适用于预测连续数值,而逻辑回归用于解决分类问题(如预测学生是否被录取),通过将数据拟合到特定曲线来处理二元结果。

当你开始机器学习之旅时,通常学到的第一个算法是线性回归。线性回归使用以下方程画出一条直线:

y=mx+c

这条直线非常适合预测连续数值,例如房屋价格或学生的分数。但是,如果你想预测一个类别会发生什么呢?例如,根据考试成绩预测学生是否被录取(1)或未被录取(0)?

如果你尝试将一条直线拟合到二元数据(0 和 1)上,这条线会无限延伸。它最终会预测出像 1.5 或 -0.4 这样不可能的值。因为直线无法对离散的选择进行分类,所以引入了逻辑回归。

历史注记:统计学家大卫·考克斯(David Cox)于 1958 年推广了逻辑回归的数学基础,用于分析二元数据集,并改编自皮埃尔·弗朗索瓦·韦吕勒(Pierre François Verhulst)在 1838 年首次提出的“逻辑曲线”,以模拟人口增长。

逻辑回归不画直线,而是将输出压缩成严格介于 0 和 1 之间的 S 形曲线。这使得算法能够输出清晰的概率(例如,被录取的概率为 85%)。

逻辑回归的步骤(训练循环)

为了了解计算机是如何学习的,让我们跟踪一个包含两个输入(CGPA 和 IQ)以预测二元输出(已录取:1,未录取:0)的小型数据集。

学生CGPA ( X1 )IQ ( X2 )实际录取状态 ( Y )
学生 18.01101
学生 25.0900

步骤 1:初始化权重和偏置

如果有 n 个特征,我们需要 n 个权重加上 1 个额外的截距项(称为偏置或 β0 )。对于我们的 2 个特征,我们需要 2+1=3 个权重。计算机会将它们全部初始化为零:

import numpy as np

# n = 特征数量(CGPA, IQ)
n = 2
weights = np.zeros(n)  # 数组: [0.0, 0.0]
bias = 0.0             # 标量: 0.0

步骤 2:进行预测并计算损失

模型使用其当前权重为每个学生计算一个原始线性得分( z ):

由于我们当前的所有权重均为 0,学生 1 得到的得分为 z=0 。我们将这个 z 输入到 Sigmoid 函数中,将其转换为概率( p ):

现在,我们使用二元交叉熵(BCE)损失来检查猜测有多糟糕。单行的公式为:

对于学生 1 (

  Y=1, p=0.5

): 

  Loss = −[1⋅log(0.5) + 0] = −(−0.693) = 0.693


对于学生 2 (

  Y=0, p=0.5

): 

  Loss = −[0 + 1⋅log(1 − 0.5)] = −(−0.693) = 0.693


平均总损失: 

  (0.693 + 0.693) / 2 = 0.693

步骤 3:使用梯度下降更新权重

为了降低这种误差,我们计算损失相对于每个参数的导数(梯度)。数学运算简化得非常优美:

让我们看看学生 1(预测 p=0.5 ,实际 Y=1 ):

Error = 0.5 − 1 = −0.5

我们通过将此误差乘以学生的特征值和我们的学习率( lr=0.1 )来计算权重更新。由于我们要降低损失,我们减去梯度:

计算机会重复步骤 2 和步骤 3 数千次。随着时间的推移,损失从 0.693 逐渐下降到接近 0。假设训练完成后,我们的优化参数变为:

  bias = −15




  w1 (CGPA) = 1.5




  w2 (IQ) = 0.05

让我们验证学生 1(CGPA=8.0, IQ=110)的计算:

计算

zzz

:

z=−15+(1.5×8.0)+(0.05×110)=−15+12+5.5=+2.5z = -15 + (1.5 \times 8.0) + (0.05 \times 110) = -15 + 12 + 5.5 = +2.5z=−15+(1.5×8.0)+(0.05×110)=−15+12+5.5=+2.5

计算

ppp

(Sigmoid):

p=11+e−2.5=11+0.082=11.082≈0.924(92.4p = \frac{1}{1 + e^{-2.5}} = \frac{1}{1 + 0.082} = \frac{1}{1.082} \approx 0.924 \quad (92.4%)p=1+e−2.51​=1+0.0821​=1.0821​≈0.924(92.4

阈值检查:由于

0.924≥0.50.924 \ge 0.50.924≥0.5

,模型自信地预测为 1(已放置)。数学运算无误!

重要概念简单解释

  1. Sigmoid 函数

Sigmoid 函数是那个将任何实数(从负无穷大到正无穷大)压缩到 0 到 1 之间整洁区间的数学魔法师。

数学公式:

如何阅读曲线图:

如果 

  zzz

 是一个很大的正数(例如 +5), 

  e−5e^{-5}e−5

 几乎变为 0,因此 

  11+0=1\frac{1}{1+0} = 11+01​=1

 。
如果 

  zzz

 恰好为 0, 

  e0=1e^{0} = 1e0=1

 ,因此 

  11+1=0.5\frac{1}{1+1} = 0.51+11​=0.5

 。
如果 

  zzz

 是一个很大的负数(例如 -5), 

  e−(−5)=e5e^{-(-5)} = e^5e−(−5)=e5

 ,使得分母变得巨大,因此输出值降至接近 0。
  1. Logit 函数(对数几率)

你可能会听到人们谈论“Logit”函数。它仅仅是 Sigmoid 函数的确切数学逆运算。它不是将分数转换为概率,而是将概率转换回直线分数。

  1. 二元交叉熵(BCE)与分类交叉熵(CCE)

这些是用于衡量误差的公式。

BCE(二元):仅适用于两种选择(0 或 1)的情况。它只检查单个正确类别的概率。
CCE(分类):适用于多种选择的情况(例如,预测图像是猫、狗还是鸟)。它在多个类别分布上衡量误差。
  1. Softmax 函数

虽然 Sigmoid 处理的是二元项目,但 Softmax 是 Sigmoid 的多类版本。如果你要在猫、狗和鸟之间进行选择,Softmax 会同时处理所有输出通道,并确保它们各自的概率之和恰好等于 1.0(100%)。

从头开始的完整工作代码

以下是使用纯 Python 和 numpy 编写整个数学循环的方法:

import numpy as np

class CleanLogisticRegression:
    def __init__(self, lr=0.1, num_iterations=1000):
        self.lr = lr
        self.num_iterations = num_iterations
import numpy as np
        self.weights = None
        self.bias = None

    def _sigmoid(self, z):
        return 1 / (1 + np.exp(-z))

    def fit(self, X, y):
        num_samples, num_features = X.shape
        # 步骤 1:将参数初始化为零
        self.weights = np.zeros(num_features)
        self.bias = 0.0

        # 步骤 4:优化循环
        for _ in range(self.num_iterations):
            # 步骤 2:线性组合和 Sigmoid 激活
            linear_model = np.dot(X, self.weights) + self.bias
            y_predicted = self._sigmoid(linear_model)

            # 步骤 3:计算梯度
            dw = (1 / num_samples) * np.dot(X.T, (y_predicted - y))
            db = (1 / num_samples) * np.sum(y_predicted - y)

            # 步骤 3:更新参数(梯度下降)
            self.weights -= self.lr * dw
            self.bias -= self.lr * db

    def predict(self, X):
        linear_model = np.dot(X, self.weights) + self.bias
        y_predicted = self._sigmoid(linear_model)
        # 应用 0.5 阈值逻辑
        return [1 if i >= 0.5 else 0 for i in y_predicted]

# 使用我们的学生数据进行快速测试
X_train = np.array([[8.0, 110], [5.0, 90]])
y_train = np.array([1, 0])

scratch_model = CleanLogisticRegression(lr=0.1, num_iterations=5000)
scratch_model.fit(X_train, y_train)
print("Scratch Trained Weights:", scratch_model.weights)
print("Scratch Trained Bias:", scratch_model.bias)

如何在 Scikit-Learn 中使用

在工业环境中,你无需从头编写代码。你可以使用 Python 内置的 scikit-learn 框架:

from sklearn.linear_model import LogisticRegression

# 1. 使用选定的超参数初始化模型
# 'penalty' 控制正则化以防止过拟合
# 'C' 控制参数强度(较小的 C 意味着更强的正则化)
model = LogisticRegression(penalty='l2', C=1.0, max_iter=1000)

# 2. 使用 fit 函数训练模型
model.fit(X_train, y_train)

# 3. 查看学习到的系数
print("Sklearn Weights:", model.coef_)
print("Sklearn Intercept:", model.intercept_)

# 4. 对新传入的数据进行预测 (CGPA = 7.2, IQ = 105)
new_student = [[7.2, 105]]
prediction = model.predict(new_student)
probability = model.predict_proba(new_student)

print(f"Prediction Class: {prediction}")
print(f"Probabilities (Not Placed vs Placed): {probability}")

核心超参数详解:

penalty: 可设置为 'l1' 或 'l2'。它向损失函数添加一个数学惩罚分数,以防止单个权重变得过大,从而保持模型的稳定性并防止过拟合。
C: 正则化强度的倒数。如果你将 C 设置为一个非常小的数字(如 0.01),你是在告诉模型:“让权重尽可能接近零。”如果你将其设置得较大(如 100),你是在告诉模型:“完全专注于完美地拟合训练数据点。”
max_iter: 这是你允许梯度下降算法执行以找到理想权重的最大循环次数。 

译文已达到本站中文翻译的字数上限,剩余内容请查看原文。

阅读原文