观文听傑

返回

上一篇用 L2 正则化约束了连续预测模型的权重。现在进入经典机器学习的第一个分类模型:面对“客户是否流失”“肿瘤是否恶性”这类二分类问题,我们既要一个类别,也常常需要一个可比较的风险分数。

最直接的想法是先用线性回归预测 0 或 1,再以 0.5 为阈值。但线性回归输出没有上下界,加入一个极端样本就可能把整条拟合直线拉偏;1.7-0.4 也不能直接解释为概率。

逻辑回归(Logistic Regression)保留了线性模型清晰的几何结构,却改变了输出的含义。本文只回答三个紧密问题:线性分数如何变成概率、概率阈值如何变成决策边界,以及交叉熵如何学习这条边界。

01 为什么“线性回归后截断”不是好分类器?#

设一维输入 xx 表示某项风险指标,标签 y{0,1}y\in\{0,1\}。线性回归拟合:

y^=wx+b\hat y=wx+b

若训练点是 (1,0)、(2,0)、(3,1)、(4,1),一条直线也许能让 x2.5x\ge 2.5 的样本超过 0.5。但加入一个很远的正类点 (20,1) 后,平方误差会强烈关注这个点的残差,斜率和截距都可能改变,原来的分类阈值随之移动。

y
1.0 │          ●  ●                         ● 极端正类点
    │        ╱                       _______╱
0.5 │──────╳──── 分类阈值       ───╳────────  新交点
    │    ╱
0.0 │ ●  ●
    └────────────────────────────────────────► x
text

问题不是“输出后裁剪到 [0,1][0,1]”就能修复的:裁剪区间外梯度为 0,而且平方误差仍在拟合连续数值 0 和 1,没有直接刻画类别概率的似然。

我们需要一个模型满足:

  1. 输出严格位于 (0,1)(0,1),可解释为正类概率;
  2. 参数仍通过可导目标学习;
  3. 最终边界仍能看出每个特征怎样推动预测。

02 先线性打分,再映射为概率#

对一批 NN 个样本、每个样本 DD 个特征,逻辑回归先计算线性分数:

z=Xw+bz=Xw+b

再通过 S 形函数(Sigmoid Function):

p=σ(z)=11+ezp=\sigma(z)=\frac{1}{1+e^{-z}}

张量形状沿数据流变化如下:

X [N,D] ──矩阵乘──► z=Xw+b [N]
             w [D]       │
             b []        ▼ sigmoid
                      p=P(y=1|x) [N]
                           │ threshold τ

                     y_pred [N]
text
  • XRN×DX\in\mathbb{R}^{N\times D}:设计矩阵,每行一个样本;
  • wRDw\in\mathbb{R}^{D}:特征权重;
  • bRb\in\mathbb{R}:截距;
  • zRNz\in\mathbb{R}^{N}:对数几率分数(Logit);
  • p(0,1)Np\in(0,1)^N:每个样本属于正类的估计概率。

Sigmoid 单调递增,因此 zz 越大,正类概率越高:

zzp=σ(z)p=\sigma(z)模型含义
2.197-2.1970.100.10负类几率约为正类的 9 倍
000.500.50两类等可能
2.1972.1970.900.90正类几率约为负类的 9 倍

03 “对数几率”为什么会变成线性函数?#

概率 pp 对应的几率(Odds)为:

odds=p1p\operatorname{odds}=\frac{p}{1-p}

它表示“正类概率是负类概率的多少倍”。对几率取自然对数,得到对数几率(Log-Odds):

logp1p=z=wx+b\log\frac{p}{1-p}=z=w^\top x+b

把上式对 pp 求解,正好得到 Sigmoid。因此逻辑回归的核心假设不是“概率与特征线性”,而是:对数几率与特征线性。

若某个特征 xjx_j 增加 1,而其他特征不变,对数几率增加 wjw_j;几率则乘以 ewje^{w_j}。例如 wj=log20.693w_j=\log2\approx0.693,该特征每增加一个单位,预测正类几率乘以 2。

特征尺度同样影响系数含义:年龄增加 1 岁与收入增加 1 元不是可比较的变化。解释系数前必须记录单位;若加入正则化,通常还应在防泄漏 Pipeline 中标准化。

04 决策边界究竟在哪里?#

默认阈值 τ=0.5\tau=0.5 时:

p0.5    z0    wx+b0p\ge0.5 \iff z\ge0 \iff w^\top x+b\ge0

所以决策边界是:

wx+b=0w^\top x+b=0

二维情况下,x=[x1,x2]x=[x_1,x_2]^\top,边界为一条直线;更高维时是超平面(Hyperplane)。向量 ww 垂直于边界,并指向正类分数增大的方向。

x₂
▲        +       +      正类:wᵀx+b > 0
│     +       +
│  - - - - - - - - -   边界:wᵀx+b = 0
│    ○      ○
│ ○     ○                 负类:wᵀx+b < 0
└──────────────────────► x₁
             ↗ w(边界法向量)
text

若业务阈值改成任意 τ(0,1)\tau\in(0,1),边界不再是 z=0z=0,而是:

zlogτ1τz\ge\log\frac{\tau}{1-\tau}

例如要求 p0.8p\ge0.8 才触发人工复核,则 logit 至少为 log41.386\log4\approx1.386。这会沿法向量平移边界,却不重新训练模型。阈值必须在验证集上按漏报和误报成本选择,不能用测试集调。

05 用三个点手算概率、损失与一步更新#

只用一个特征且设 b=0b=0

x = [1, 2, 3]
y = [0, 0, 1]
w = 0
text

此时三个 logit 都是 0,概率都是 0.5。平均二元交叉熵(Binary Cross-Entropy,BCE)为:

J(w)=13i=13[yilogpi+(1yi)log(1pi)]=log0.50.693J(w)=-\frac{1}{3}\sum_{i=1}^{3} \left[y_i\log p_i+(1-y_i)\log(1-p_i)\right] =-\log0.5\approx0.693

上一篇分类损失文章已经推导过单样本 Li/zi=piyi\partial L_i/\partial z_i=p_i-y_i。结合 zi=wxiz_i=wx_i

Jw=13i=13xi(piyi)\frac{\partial J}{\partial w} =\frac{1}{3}\sum_{i=1}^{3}x_i(p_i-y_i)

代入数值:

Jw=1(0.50)+2(0.50)+3(0.51)3=0\frac{\partial J}{\partial w} =\frac{1(0.5-0)+2(0.5-0)+3(0.5-1)}{3}=0

梯度竟然为 0。不是模型已经学好,而是“两个较小的负类点”和“一个较大的正类点”在当前坐标中刚好抵消。若同时学习截距:

Jb=13i(piyi)=0.53>0\frac{\partial J}{\partial b}=\frac{1}{3}\sum_i(p_i-y_i)=\frac{0.5}{3}>0

截距仍会向负方向更新。这个极小例子提醒我们:截距不是装饰;中心化、样本分布和特征相关性都会影响梯度。

再看单个正样本 x=2,y=1,w=0,b=0x=2,y=1,w=0,b=0。梯度为:

Lw=x(py)=2(0.51)=1\frac{\partial L}{\partial w}=x(p-y)=2(0.5-1)=-1

取学习率 η=0.2\eta=0.2

wnew=00.2(1)=0.2w_{new}=0-0.2(-1)=0.2

新 logit 为 0.40.4,新概率为 σ(0.4)0.599\sigma(0.4)\approx0.599,损失从 0.6930.693 降到 log0.5990.513-\log0.599\approx0.513

06 不调用 fit,先写出训练本体#

下面用 NumPy 明确完成前向、稳定交叉熵、梯度和更新。np.logaddexp(0, z)-yz 等价于二分类负对数似然,能避免直接计算 log(sigmoid(z)) 的溢出问题。

需要调试的最小不变量:

assert X.ndim == 2 and y.shape == (X.shape[0],)
assert w.shape == (X.shape[1],)
assert logits.shape == probabilities.shape == y.shape
assert np.isfinite(objective)
assert np.isfinite(grad_w).all() and np.isfinite(grad_b)
python

07 用当前 scikit-learn API 落地#

截至本文写作时,scikit-learn 1.9 的 LogisticRegression 默认执行正则化逻辑回归;C 是正则化强度的倒数,越小约束越强。1.8 起 penalty 参数已经弃用,因此新代码用 l1_ratioC 表达正则化类型。

重要接口语义:

  • decision_function(X) 返回二分类中 classes_[1] 的有符号分数;大于 0 时默认预测该类;
  • predict_proba(X) 的列顺序由 classes_ 决定,不能永远假设第二列就是业务正类;
  • coef_ 在二分类中形状为 [1,D]intercept_[1]
  • C=np.inf 表示无正则化,但通常应通过交叉验证选择有限 C
  • max_iter 是求解器迭代上限,不是小批量训练的 epoch 数;若出现 ConvergenceWarning,先标准化并检查尺度,再考虑增加它。

标准化必须在 Pipeline 内部,让每个交叉验证折只用本折训练数据计算均值和方差。

08 训练、阈值选择与推理不要混成一步#

训练集
  └── 学 w,b 与预处理统计量

验证集     ▼
  ├── 选 C、特征与模型
  └── 按成本选概率阈值 τ
           │ 全部冻结
测试集     ▼
  └── 一次最终验收

线上请求 ──► 同一预处理 ─► p ─► τ ─► 动作
text

模型输出 0.7 并不自动意味着“必须判正类”。若漏掉恶性病例代价远大于误报,可以降低阈值;若人工复核资源紧张,可以提高阈值。阈值改变的是决策规则,不改变模型已经学到的概率排序。

还要区分 区分能力(Discrimination)概率校准(Calibration):模型可能把正样本普遍排在负样本前面,却让“预测 0.8”的样本只有 60% 真为正类。交叉熵训练有概率语义,但有限数据、正则化和分布漂移仍会破坏校准。

09 常见错误与调试路径#

  1. 把类别编码顺序想当然。 总是打印 classes_,按业务正类定位概率列。
  2. 把 logit 当概率。 decision_function 可为任意实数;只有 predict_proba 位于 [0,1][0,1]
  3. 忽略标准化。 不同尺度会让求解器收敛变慢,也让 L2 对各系数的约束失衡。
  4. 误解 C C 越大正则化越弱,与 Ridge 的 alpha 方向相反。
  5. 盲目提高 max_iter 若损失不收敛,先查非有限值、尺度、完全分离和重复特征。
  6. 在测试集选阈值。 这会把测试信息带入开发;阈值是超参数,应在验证集确定。
  7. 只看准确率。 类别失衡时,同时记录对数损失、精确率、召回率和混淆矩阵。
  8. 把系数当因果效应。 相关特征、选择偏差和遗漏变量会改变系数;预测关联不等于干预因果。

可先检查:

model = search.best_estimator_.named_steps['logisticregression']
assert np.isfinite(model.coef_).all()
assert np.isfinite(model.intercept_).all()
assert np.allclose(probabilities.sum(axis=1), 1.0)
print('classes:', search.classes_)
print('iterations:', model.n_iter_)
print('logit range:', logits.min(), logits.max())
python

若训练和验证都接近随机,检查特征是否真的含信号、标签是否错位;若训练很好而验证很差,回到学习曲线与正则化诊断;若线上概率整体偏高或偏低,检查分布漂移与校准,而不是只移动阈值掩盖问题。

10 它何时会失败?与相近方法怎样区分?#

逻辑回归默认只有线性决策边界。对“同心圆”或异或(XOR)结构,原始特征空间中不存在一条直线分开两类;必须构造非线性特征、使用核方法、树模型或神经网络。

完全分离时,未正则化最大似然会不断放大系数,让训练概率逼近 0 和 1,却没有有限最优参数;默认正则化能缓解,但不能创造新信息。

方法学到什么概率输出决策边界主要区别
逻辑回归一组全局线性权重原生 Sigmoid / Softmax线性可解释、训练与推理快
线性回归阈值化连续目标的平方误差拟合无可靠概率含义线性目标与分类不匹配
线性 SVM最大间隔超平面默认不是概率线性更关注边界附近样本与间隔
K 近邻保存训练实例并局部投票邻域票数比例高度非线性几乎不训练,推理成本高
决策树特征阈值规则叶节点频率轴对齐分段自动表示非线性交互但易高方差

它还会在标签噪声严重、极端类别失衡、预测人群与训练人群不同、关键交互未进入特征时失败。清晰的线性边界是优点,也是表达能力的上限。

11 今天真正需要记住什么?#

  1. 逻辑回归先计算线性 logit,再用 Sigmoid 得到正类概率;线性的是对数几率,不是概率本身。
  2. 默认 0.5 阈值对应 wx+b=0w^\top x+b=0,所以二分类边界是超平面,ww 是其法向量。
  3. BCE 梯度通过 pyp-y 调整权重;稳定实现应直接在 logits 上计算损失。
  4. scikit-learn 的 C 越小正则化越强,概率列顺序必须按 classes_ 读取。
  5. 训练参数、选择正则化和选择业务阈值属于不同阶段,测试集只做最后验收。

12 思考题与小练习#

练习 1:从概率还原 logit

若模型输出正类概率 0.8,则 z=log[0.8/(10.8)]=log41.386z=\log[0.8/(1-0.8)]=\log4\approx1.386。若阈值也是 0.8,这个样本恰好位于新决策边界上。

练习 2:画出一条二维边界

给定 w=[2,1]w=[2,-1]b=3b=-3,边界为 2x1x23=02x_1-x_2-3=0,即 x2=2x13x_2=2x_1-3。判断点 (2,0)(2,0) 的类别:logit 为 1,默认阈值下预测正类,概率约为 0.731。

练习 3:验证正则化方向

把网格改为 C=[0.001, 1, 1000],记录训练对数损失、验证对数损失和系数范数。解释为什么小 C 往往让系数更小,而最大 C 不一定给出最好验证结果。

相关工作#

13 下一篇预告#

逻辑回归用一组全局权重画出一条线性边界。如果类别边界弯弯曲曲,但相似样本往往拥有相同标签,能否不假设全局公式,直接询问“离新样本最近的训练点是谁”?下一篇将进入 K 近邻,追踪距离计算、局部投票、特征尺度与维度灾难。

一条直线怎样输出分类概率?从对数几率到逻辑回归决策边界
https://zwjcode.cn/blog/logistic-regression-probability-boundary
作者
发布于 2026年8月21日
版权协议 CC BY-NC-SA 4.0
评论加载似乎遇到了问题,请尝试刷新页面。