Logistic 与分类决策
本章目录
学完后,你应能独立完成
- 从Bernoulli似然推交叉熵、梯度与Hessian
- 解释可分数据的无正则MLE问题
- 区分权重、阈值、校准与排序分数
前置建议:损失、泛化与优化
改变一个条件,观察发生什么
浏览器内即时教学计算;Python 实验结果另列于代码区。图形与数值一起核对。
从log odds进入概率
令Z=[1,X],θ含截距,z=Zθ,p=σ(z)。logit(p)=log[p/(1−p)]=z,线性的是log odds,不是概率本身。β_j变化对应条件odds ratio,不是固定的概率差。
在这个模型中,类别概率从特征映射而来;这并不要求每类X都正态。decision score可用于排序,但只有经过明确概率映射和校准评价,才讨论概率含义。
从似然到可稳定计算的损失
独立工作似然写作∏p_i^{y_i}(1−p_i)^{1−y_i}。取平均负log并代入sigmoid,得到softplus(z)−yz。实际面板的依赖不因此消失;损失可以作为训练准则,推断还需相应条件。
- 单样本对z求导得到σ(z)−y。
- 链式法则乘Z,再对样本平均:g=Zᵀ(p−y)/n。
- 对p再求导,H=ZᵀWZ/n,W对角项p(1−p)。
- 使用logaddexp与稳定expit,避免exp(1000)溢出。
凸为何还没有有限最优解
H半正定说明凸,但完全可分数据上,可以不断放大分离方向的系数,让正确标签的概率趋1、损失趋0,却没有有限的无正则最优θ。出现大系数、近零训练loss不代表可可靠外推。
惩罚可以控制斜率和稳定性,仍需考虑未惩罚截距及退化标签。普通Wald不可靠时直接改普通LR也不自动恢复失效的MLE与渐近条件。
类别权重与阈值改变不同对象
类别权重改变拟合风险。理想情况下,加权最优输出q=w₁p/[w₁p+w₀(1−p)],不能自动当原总体的真实p。选择阈值改变决策;校准调整输出概率的解释,它们不是同一操作。
ROC-AUC反映排序,严格单调变换不改它;logloss关心概率质量,会改变。少数类任务还应看PR/AP和基准比例;AP并非一般等于PR曲线梯形面积。阈值与校准只能在合法开发数据里选择。
分类如何用于股票研究
上涨概率、超阈值概率与收益金额相关但不等同。50%胜率在盈亏幅度不同、成本不同的政策中含义不同。分数排序也未必给可交易的长仓收益。先明确目标、收益金额、交易与成本,再选择概率决策。
库中的C是逆惩罚参数,但归一化、样本权重与solver会影响对应关系,不无条件写C=1/λ。下方教学GD使用显式平均损失且无正则,输入已经包含截距。
从算法到一次真实运行
代码在本地 Python 中执行,HTML 内展示参考实现和本轮运行结果。请先独立完成练习,再展开完整参考文件。
def logistic_loss_grad(Z, y, theta):
"""Z already includes an intercept column; mean negative log likelihood."""
z = Z@theta
loss = np.mean(np.logaddexp(0, z)-y*z)
grad = Z.T@(expit(z)-y)/len(Z)
return float(loss), grad
def logistic_gd(Z, y, rate=.1, steps=300):
theta = np.zeros(Z.shape[1]); history = []
for _ in range(steps):
loss, grad = logistic_loss_grad(Z,y,theta)
history.append(loss)
theta -= rate*grad
return theta, np.asarray(history)"""Standalone synthetic teaching example. Run locally with Python, not in the HTML."""
import json
import numpy as np
import pandas as pd
from scipy.special import expit
def clean(value):
if isinstance(value, dict): return {str(k):clean(v) for k,v in value.items()}
if isinstance(value,(list,tuple,np.ndarray)): return [clean(v) for v in value]
if isinstance(value,(np.integer,)): return int(value)
if isinstance(value,(float,np.floating)): return float(value) if np.isfinite(value) else None
if isinstance(value,(np.bool_,)): return bool(value)
return value
def print_result(result):
print(json.dumps(clean(result),ensure_ascii=False,allow_nan=False))
def logistic_loss_grad(Z, y, theta):
"""Z already includes an intercept column; mean negative log likelihood."""
z = Z@theta
loss = np.mean(np.logaddexp(0, z)-y*z)
grad = Z.T@(expit(z)-y)/len(Z)
return float(loss), grad
def logistic_gd(Z, y, rate=.1, steps=300):
theta = np.zeros(Z.shape[1]); history = []
for _ in range(steps):
loss, grad = logistic_loss_grad(Z,y,theta)
history.append(loss)
theta -= rate*grad
return theta, np.asarray(history)
if __name__ == "__main__":
x=np.linspace(-2,2,20)
Z=np.column_stack([np.ones(len(x)),x])
y=np.array([0,0,0,1,0,0,0,1,0,1,0,1,1,1,1,0,1,1,1,1])
theta,history=logistic_gd(Z,y,rate=.2,steps=500)
assert history[-1]<history[0]
loss,gradient=logistic_loss_grad(np.array([[-1.],[1.]]),np.array([0.,1.]),np.zeros(1))
np.testing.assert_allclose([loss,gradient[0]],[np.log(2),-.5])
print_result({"theta":theta,"initial_loss":history[0],"final_loss":history[-1],
"probability_first_last":expit(Z@theta)[[0,-1]],"hand_gradient":gradient})
查看本轮本地运行记录 · 2026-10-12
{
"theta": [
0.3184732197603453,
1.3411988071129484
],
"initial_loss": 0.6931471805599453,
"final_loss": 0.48090523464636775,
"probability_first_last": [
0.08596533259294216,
0.9526134526916358
],
"hand_gradient": [
-0.5
]
}先回答,再看提示和答案
无截距x=[−1,1]、y=[0,1]、β=0的梯度多少?
一级提示
先对logit求导,再乘x。
参考答案与条件
p=.5,g=mean[x(p−y)]=−.5,学习率.1更新为β=.05。
w₁=2,w₀=1,原p=.5,加权最优q多少?
一级提示
先写出目标、信息集和所需条件。
参考答案与条件
2/3。类别权重改变风险,输出不直接等于原总体概率。
AUC很高,概率一定校准好吗?
一级提示
先写出目标、信息集和所需条件。
参考答案与条件
不是。排序与概率质量不同,单调变换能保AUC而改变logloss及校准。
把知识迁移到一个新任务
实现稳定loss与梯度、GD训练、有限差分。将toy标签改为完全可分,观察系数范数与loss;解释为什么不能用无限加轮数解决识别问题。
这里保存学习笔记,不在浏览器执行 Python。A/B/C 由你按独立完成程度填写。
参考与进一步阅读
在线文档可能比本地固定版本更新;API 行为以已验证代码和版本记录为准。
掌握状态与复习
关掉资料独立完成后记 A;提示后完成记 B;需要重学记 C。
记录尽量保存在当前浏览器,建议定期导出备份。