dev.to #ai短讯
逻辑回归简介
文章介绍了机器学习入门算法逻辑回归。指出线性回归适用于预测连续数值,而逻辑回归用于解决分类问题(如预测学生是否被录取),通过将数据拟合到特定曲线来处理二元结果。
当你开始机器学习之旅时,通常学到的第一个算法是线性回归。线性回归使用以下方程画出一条直线:
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 ) |
|---|---|---|---|
| 学生 1 | 8.0 | 110 | 1 |
| 学生 2 | 5.0 | 90 | 0 |
步骤 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(已放置)。数学运算无误!
重要概念简单解释
- 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。- Logit 函数(对数几率)
你可能会听到人们谈论“Logit”函数。它仅仅是 Sigmoid 函数的确切数学逆运算。它不是将分数转换为概率,而是将概率转换回直线分数。
- 二元交叉熵(BCE)与分类交叉熵(CCE)
这些是用于衡量误差的公式。
BCE(二元):仅适用于两种选择(0 或 1)的情况。它只检查单个正确类别的概率。
CCE(分类):适用于多种选择的情况(例如,预测图像是猫、狗还是鸟)。它在多个类别分布上衡量误差。- 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: 这是你允许梯度下降算法执行以找到理想权重的最大循环次数。 译文已达到本站中文翻译的字数上限,剩余内容请查看原文。