标签:逻辑回归 | 机器学习 | 二元分类 | 隐含变量 | 初学者
写给谁看的?
如果你刚刚学完线性回归,却发现它一遇到"买/不买"这类 Yes/No 问题就失灵,这篇就是为你写的。
不需要任何高级数学,只要会加乘、能看懂漫画就能跟上。文末附 Python 逐行代码,复制即可跑。
01 线性模型为何不能直接做分类?
先做一个实验:用线性回归预测"今天会不会下雨"(0=不下,1=下)。
| 气压(hPa) | 是否下雨 |
|---|---|
| 1013 | 0 |
| 1000 | 1 |
| 990 | 1 |
把线性回归 fit 后,决策规则设为:
若 ŷ ≥ 0.5 就预测 1,否则 0。
很快就发现 3 个 bug:
- 输出值可能 >1 或 <0,根本不像"概率"。
- 远离样本点的微小扰动会让预测从 0.1 蹦到 1.3,鲁棒性极差。
- 最小二乘的误差平方惩罚对"分类对错"并不敏感。
一句话:线性回归输出的是实数,而分类需要 0/1 这两个离散符号。
02 从"购物"故事理解隐含变量
想象你正在逛淘宝,脑子里有两个小人在打架:
| 小人 | 台词 | 经济学黑话 |
|---|---|---|
| ✅ 正效应 | "买它!快乐+10" | 效用 +u |
| ❌ 负效应 | "没钱!心疼-8" | 效用 −v |
只有当 净效用 y* = u − v > 0 时,你才会点"提交订单"。
u、v 谁也看不见,经济学家叫它们 latent variable(隐含变量) 。
能看到的只是最后二元结果:
y = 1(下单) 或 0(拜拜)。
03 把故事写成公式
-
隐含变量线性组合:
y* = xβ + ε
x 可以是价格、收入、优惠券数量;β 是待求系数;ε 是随机干扰。
-
观测规则:
y = 1 当且仅当 y* > 0
-
求概率:
P(y=1|x) = P(y*>0) = P(xβ + ε > 0)
只要知道 ε 的分布,就能把概率算出来。
04 两种"翻译官"Probit vs Logit
| 模型 | 假设 ε 分布 | 累积分布函数 F(z) | 尾部 |
|---|---|---|---|
| Probit | 标准正态 N(0,1) | Φ(z) | 薄 |
| Logit | 逻辑分布 | σ(z)=1/(1+e^(−z)) | 厚 |
两者都是 S 型曲线,把实数 z 压进 (0,1) 区间当概率用。
逻辑回归就是选用了 Logistic 分布的"翻译官"。
05 Logistic 函数 σ(z) 推导
逻辑分布的 CDF 自带解析式,超好求导:
σ(z) = 1 / (1+e^(−z))
性质:
- σ(−∞) = 0, σ(+∞) = 1
- 导数:σ'(z) = σ(z)(1−σ(z)) ← 后面梯度下降要用!
于是:
P(y=1|x) = σ(xβ)
06 似然函数(Likelihood)
L(β) 就是把"模型猜得有多准"量化成一个具体数字的似然函数(Likelihood Function)。β 越好,L(β) 越大;我们最终要找使 L(β) 最大的那个 β
给定 m 条样本 {(x⁽ⁱ⁾,y⁽ⁱ⁾)},y⁽ⁱ⁾∈{0,1},独立同分布:
L(β) = ∏[ σ(x⁽ⁱ⁾β)^y⁽ⁱ⁾ · (1−σ(x⁽ⁱ⁾β))^(1−y⁽ⁱ⁾) ]
解释:
"对第 i 个人,模型说自己猜对的'自信分'。"
拆开说:
-
如果真实结果是 买了(y⁽ⁱ⁾ = 1)
公式只剩前半截:σ(x⁽ⁱ⁾β)^1 = σ(x⁽ⁱ⁾β)
→ 模型给出的"他买的那一份概率"就是自信分;概率越高,越觉得"我猜得对"。
-
如果真实结果是 没买(y⁽ⁱ⁾ = 0)
公式只剩后半截:(1−σ(x⁽ⁱ⁾β))^1 = 1−σ(x⁽ⁱ⁾β)
→ 模型给出的"他不买的那一份概率"才是自信分;同样越高越好。
-
把整条连乘起来
→ "在所有样本上,模型每一次都猜对自己那份概率的乘积。"
这个乘积越大,说明参数 β 让已发生的 0/1 结果看起来越"顺理成章"。
一句话总结:
这条式子就是在给模型打"猜题得分"------猜对且越自信,得分越高。
- 当 y=1,贡献 σ(xβ);
- 当 y=0,贡献 1−σ(xβ)。
07 对数似然 & 损失函数
取对数,把连乘变连加,方便求导:
ℓ(β) = Σ [ y⁽ⁱ⁾ log σ(x⁽ⁱ⁾β) + (1−y⁽ⁱ⁾) log(1−σ(x⁽ⁱ⁾β)) ]
机器学习里常把 负对数似然当损失:
J(β) = −ℓ(β)
最小化 J(β) ⇔ 最大化似然。
08 梯度下降一步推到底
记:
p⁽ⁱ⁾ = σ(x⁽ⁱ⁾β)
误差 e⁽ⁱ⁾ = p⁽ⁱ⁾ − y⁽ⁱ⁾
则:
∂J/∂β = Xᵀ (p − y) / m
漂亮结论:梯度 = 预测概率 − 真实标签,形式与线性回归一模一样,只是里面换了 σ(·)。
更新公式:
β_{t+1} = β_t − α · Xᵀ(p−y)/m
(α 为学习率)
09 10 行 Python 实现
python
import numpy as np
from sklearn.datasets import make_classification
# 1. 造玩具数据
X, y = make_classification(n_samples=1000, n_features=4, n_redundant=0, random_state=42)
X = np.c_[np.ones(X.shape[0]), X] # 加截距项
# 2. 初始化
beta = np.zeros(X.shape[1])
lr = 0.1
# 3. sigmoid 函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))
# 4. 梯度下降
for step in range(5000):
z = X @ beta
p = sigmoid(z)
grad = X.T @ (p - y) / y.size
beta -= lr * grad
# 5. 打印结果
print("学到的系数:", beta)
10 总结一张图
线性回归 → 输出任意实数
│
│加 S 型函数
▼
逻辑回归 → 输出概率 (0,1)
│
│设定阈值 0.5
▼
二元分类 → 0/1 预测