简介:清华大学数据分析与统计学系列课程第六章PPT,以Logistic回归与最大熵模型为核心,是面向大数据与统计学习初学者的系统性教学资料。该章节基于广义线性模型框架,详细拆解逻辑斯蒂分布、Sigmoid函数、二项逻辑斯蒂回归、事件的几率与对数几率,并针对似然函数、极大似然估计、梯度下降及拟牛顿法等参数求解方法给出清晰推导,同时引入最大熵原理,结合约束条件与特征函数说明模型构建过程,有助于学习者掌握分类问题的建模思路与统计推断方法。资源为1个pptx文件,共54页,压缩包大小1.78MB,页面结构按“逻辑斯蒂回归模型—最大熵模型—模型学习的最优化方法”递进编排,适合教师授课、学生复习或从业者自学。该资源已有324人学习下载,可作为统计学、数据分析及机器学习入门阶段的重要参考,尤其适用于需要系统梳理分类模型理论基础的读者。
1. Logistic回归与最大熵模型:为什么这两个名字在统计课里总挨着
给电商团队做复购预测培训时,我问了个问题:为什么二分类任务绕不开Logistic回归?现场没人能直接答上来。更少人知道,Logistic回归和最大熵模型在清华统计学系列课程第六章里是并列出现的,而且数学上出自同一条推导路径。这两个模型一个听起来传统,一个听起来高深,其实在二分类场景下是同一个东西,区别只在推导视角。下面就从这两个名字展开,把背后的原理、最小实现和常见踩坑一次性讲透,适合正在做数据分析项目实践、又不想只调包的人。
2. 从线性回归到Logistic回归:Logit变换与极大似然估计
2.1 线性回归为什么预测不了二分类概率
先把反直觉的结论放在前面:如果你把二分类标签设为0/1,直接用最小二乘线性回归去拟合,得到的不是概率,而是「给定x条件下y的平均值」。这句话在连续目标下没问题,但在0/1目标下会出现两个硬伤。
第一个硬伤是预测值会跑出[0,1]区间。回归线不会自动遵守概率边界,当特征推到极值附近,预测值可能变成1.2或者-0.3。拿到这样一个数字,你没法把它解读成概率。第二个硬伤是误差项不满足正态假设。线性回归的系数检验依赖误差正态性,而0/1结果下误差只可能取两个值,正态性直接失效,那些p值基本不能看。
更深一层的问题是损失函数。最小二乘对远离边界的样本格外敏感,但分类任务真正关心的不是「偏离多少」,而是「分到哪一边」。一个预测值达到2.3的真实正样本,在线性回归里会拉着回归线跑,而在Logistic回归里它只贡献一个接近0的梯度。这也是为什么做分类建模的人几乎不会用线性回归估计概率。
所以需要一个新的映射:把被限制在[0,1]区间内的概率,变换到整个实数轴,再在实数轴上做线性组合。这个变换就是Logit变换,它给出的正是Logistic回归的骨架。
2.2 Logit变换与sigmoid的由来
Logit变换的定义是从「发生比」出发:
logit(p) = ln(p / (1-p)) = w^T x + b
其中p = P(y=1|x)。这个式子把odds取对数,等于一个线性表达式。反解出来就得到sigmoid函数:
p = 1 / (1 + e^{-(w^T x + b)})
这个反解值得自己手推一遍。两边取指数、整理、上下同除,三步就到。它把线性组合映射回[0,1],同时保留了线性结构——参数仍然通过线性组合影响输出。
参数估计用极大似然。对每个样本,正类和负类的概率合写成一个表达式:
P(y|x) = p^y (1-p)^{1-y}
对所有样本累加取负对数,就是交叉熵损失:
L(w) = -Σ [y_i ln p_i + (1-y_i) ln(1-p_i)]
对这个损失求梯度,结果非常干净:
∂L/∂w = Σ x_i (p_i - y_i)
这个形式的梯度和线性回归的最小二乘梯度几乎一样,但p_i是概率,被sigmoid压在0到1之间。所以异常点对参数的影响是有限的,不会像线性回归那样被极端值牵着走。我第一次推到这里挺意外:一个看起来很复杂的模型,最终落地就是「残差乘特征」的循环更新。
2.3 系数的业务解读:从log-odds到概率变化
模型训练完,业务方最爱问:这个特征的影响有多大?如果直接拿系数说「x每增加1,概率增加多少」,那是错的,因为Logistic回归的系数对概率的影响是非线性的。
正确解读路径是:w_j表示x_j增加1个单位时,log-odds增加w_j。翻译回odds,就是odds变成原来的e^{w_j}倍。举个例子:某特征系数0.7,e^{0.7}≈2.01,意思是该特征每涨1个单位,正样本的odds翻倍。如果概率基线是0.1,odds是0.111,翻倍后是0.222,对应概率约0.18,涨了8个百分点;但基线是0.5时,odds从1变2,概率变0.667,涨了近17个百分点。同一个系数在不同基线下的效果完全不同。
所以在落地报告里,我一般会给出三个数:系数、e^w、以及在典型基线(10%、50%)下换算的概率变化量。这样业务方才能直观理解这个变量值多少钱。这也是Logistic回归在商业数据分析里经久不衰的原因——它不像树模型那样只能给特征重要性排序,而是能解释「发生比」。
3. 最大熵模型:Logistic回归背后那条更硬的推导路径
3.1 最大熵原则:在没有更多信息时不过度假设
熵在信息论里定义成H(p) = -Σ p(x) log p(x),衡量一个分布的不确定性。熵越大,分布越均匀,模型对未知的假设越少。最大熵原则说的是:在满足已知约束的所有分布中,选择熵最大的那一个。逻辑很直接:只知道这些,就不要额外假设别的,否则就是在编造信息。
举个例子。假设随机变量取三个值,只知道均值是某个数。满足这个均值的分布有无穷多个,熵最大的那个是「在约束下尽量均匀」的分布,它没有引入任何额外偏好。这个思想用到分类上就是最大熵模型:给定输入x,要预测标签y的分布。训练数据提供了经验规律,模型必须满足这些规律,但不能在此基础上自己发挥。
对做数据分析的人来说,这个视角的好处是:它不预设参数结构。线性回归假设y和x是线性关系,决策树假设特征空间可以递归划分,而最大熵模型只要求模型复现训练数据里的统计约束,其余部分交给熵去平滑。所以它被称为「极少假设」的模型。
3.2 特征函数与约束的建模方式
要把「经验规律」变成数学约束,需要特征函数f_j(x, y)。常见做法是定义指示函数,比如f_j(x,y)=1当x满足某条件且y取特定值,否则为0。也可以设计成实数值特征,比如f_j(x,y)=x_j·I(y=1)。
关键约束是:特征函数在模型分布下的期望,必须等于训练数据上的经验期望。写成公式:
Σ_x Σ_y P̃(x)P(y|x)f_j(x,y) = Σ_x Σ_y P̃(x,y)f_j(x,y)
左边是模型期望,右边是从训练数据里统计出来的样本期望。P̃(x)是经验分布,也就是样本中x出现的频率。这个约束的含义是:模型必须复现数据里观察到的特征和标签之间的相关性,不能多也不能少。
除了特征约束,还有一个恒有约束:对任意x,Σ_y P(y|x)=1。这样问题就变成一个带约束的熵最大化问题。注意,模型本身没有预设P(y|x)的具体形式,所有形状都是优化出来的,这就是最大熵模型和Logistic回归在建模思路上最本质的差别。
3.3 拉格朗日对偶求解:为什么对偶空间里自然长出sigmoid
带约束的熵最大化用拉格朗日乘子法解。目标函数是熵的负值,约束是特征期望等式和归一化条件。构造拉格朗日函数后对P(y|x)求偏导并令其为零,解出来:
P(y|x) = (1/Z(x)) · exp(Σ_j λ_j f_j(x,y))
其中Z(x)是归一化因子,λ_j是第j个特征约束对应的拉格朗日乘子。这是一个指数族分布,也叫softmax形式。推到这一步,最大熵模型的代价也暴露出来:要算归一化因子Z(x),类别数少时还好,类别多了计算量会迅速上涨。
现在把二分类代进去。令y∈{0,1},特征函数取f_j(x,y)=x_j·I(y=1)。当y=0时所有特征函数都是0,当y=1时f_j=x_j。于是:
P(y=1|x) = exp(Σλ_j x_j) / (1 + exp(Σλ_j x_j))
这和上一章sigmoid表达式一模一样,只差把λ换成w。所以Logistic回归是最大熵模型在二分类、线性特征下的封闭解;最大熵模型是Logistic回归在多分类、任意特征函数下的推广。这条路径的价值在于,它告诉你Logistic回归的sigmoid不是拍脑袋选的形状,而是最大熵原则下的必然结果。
以后如果同事问Logistic和最大熵有什么关系,你可以从最大熵直接推到sigmoid,而不是只丢一句「它们等价」的结论。能把推导讲给别人听,才算真懂了这个模型。
4. 用Python跑通Logistic回归与最大熵模型:最小实现与参数经验
4.1 梯度下降训练Logistic回归的最小代码
先准备数据。用sklearn生成500个样本、5个特征,按7:3分割成训练和测试集。第一步做标准化,这是梯度下降能不能稳的关键,不标准化的学习率基本靠玄学。
import numpy as np from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split # 生成一个二分类数据集:500个样本,5个特征,3个有效特征 X, y = make_classification(n_samples=500, n_features=5, n_informative=3, n_redundant=0, random_state=42) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42) # 标准化:用训练集的均值和方差变换测试集,避免数据泄漏 mu, sigma = X_train.mean(axis=0), X_train.std(axis=0) X_train = (X_train - mu) / (sigma + 1e-8) X_test = (X_test - mu) / (sigma + 1e-8) # 加一列1作为截距项 Xb = np.hstack([np.ones((X_train.shape[0], 1)), X_train]) w = np.zeros(Xb.shape[1]) lr = 1.0 for i in range(5000): p = 1 / (1 + np.exp(-Xb @ w)) grad = Xb.T @ (p - y_train) / len(y_train) w -= lr * grad逻辑说明:循环体里只有两行,第一行用当前参数算所有样本的正类概率,第二行算梯度并更新参数。核心是Xb.T @ (p - y_train) / len(y_train),它等价于Σ x_i (p_i - y_i)再取平均。除以样本量让梯度尺度和数据规模解耦,改数据量时学习率不用跟着大改。
参数说明:lr=1.0在标准化后是安全值,不标准化时这个学习率大概率发散。迭代5000次是留足余量,实际跑2000次左右loss就不再降。想确认收敛,在循环里每100次打印一次交叉熵损失即可。
4.2 最大熵模型GIS迭代的最小实现
最大熵模型的经典训练算法是GIS(Generalized Iterative Scaling)。它不计算损失梯度,而是让「模型期望」逐步逼近「样本期望」,每次按对数比例缩放参数。
def train_maxent(X, y, C=5.0, n_iter=100): # 特征函数 f_j = x_j * (y=1),要求特征非负 emp = X[y == 1].mean(axis=0) lam = np.zeros(X.shape[1]) for _ in range(n_iter): p1 = 1 / (1 + np.exp(-X @ lam)) model = (X * p1[:, None]).mean(axis=0) lam += (1.0 / C) * np.log((emp + 1e-9) / (model + 1e-9)) return lam逻辑说明:emp是样本经验期望,这里用正样本特征均值表示;model是模型当前参数下的期望。两者相等时,log比值为0,参数不再更新。加1e-9是防除零。C来自GIS算法对特征总出现次数的约束,C越大每次更新步长越小,越稳但收敛越慢。
参数说明:特征必须非负,否则log里会出现负值。常见做法是先做MinMaxScaler把特征压到[0,1],再做GIS。C取5.0、迭代100次是经验起点;特征数量到几百时,把C提到特征最大出现次数附近,迭代设到500轮。跑完可以把上一节梯度下降得到的w(去掉截距项后)和GIS得到的λ对比,两者方向一致、数值近似,因为在同一个凸目标下收敛到同一个最优解。
评估模型是否正常,用测试集算准确率和AUC:
from sklearn.metrics import roc_auc_score prob = 1 / (1 + np.exp(-np.hstack([np.ones((X_test.shape[0], 1)), X_test]) @ w)) acc = ((prob > 0.5) == y_test).mean() auc = roc_auc_score(y_test, prob) print(f"Accuracy: {acc:.3f}, AUC: {auc:.3f}")逻辑说明:prob是测试集正类概率,直接用0.5作阈值得到预测标签,再和真实标签比较。AUC不受阈值影响,衡量的是排序能力。这两个指标在二分类里要一起看,单独一个都可能骗人。
4.3 收敛判断与关键参数的经验值
正则化强度。sklearn的LogisticRegression里C是正则化强度的倒数,C越小正则越强,默认1.0对很多数据集偏弱。我一般用GridSearchCV在logspace(-3, 3, 7)扫一遍。最大熵模型GIS没有内置正则化,只能靠提前停止控制过拟合,迭代到模型期望和样本期望的差距不再下降就停下来。
收敛判断不要只看参数变化量。参数变平缓不代表损失在降,我一般同时盯两个量:交叉熵损失和对数似然。损失连续10轮下降小于1e-5才算收敛。数据量大的项目里还会加一个watchdog,一旦出现NaN立刻回退上一轮参数,防止训练直接翻车。
批大小的选择。样本量小用全量梯度下降最稳;数据量到几十万以上,用SGD或Adam。Logistic回归用SGD时,学习率从0.1开始,每个epoch乘0.99做退火。批大小不要低于32,否则梯度噪声太大;这个经验在表格数据上比在图像数据上更明显。
4.4 何时从手写实现切回成熟库
上面的手写代码价值在看清数学,实际项目里直接用sklearn或者statsmodels。手写一遍能让你理解梯度公式怎么来、标准化为什么重要、收敛行为有什么坑,这些高层API不会教。但到真实数据集上,缺失值、稀疏特征、大样本这些环节,成熟库的求解器(liblinear、lbfgs)经过了大量场景打磨,稳定性和速度都远超自己写的循环。
常见做法是:先手写一份小规模代码确认思路,再切到LogisticRegression跑全量数据。这样既能享受库的工程优势,又不会把模型当黑匣子。对做python数据分析与可视化实践的人来说,这个习惯能帮你从「能跑」进阶到「真懂」。
5. Logistic回归落地避坑:5条从数据到收敛的血泪记录
5.1 特征没标准化,梯度下降像在走迷宫
现象:手写实现时loss曲线下降缓慢,几千轮还没收敛;或者学习率调大了直接NaN。
原因:特征量纲差异大时,损失函数的等值线是拉长的椭圆,梯度方向不指向椭圆中心,而是被数值范围大的特征主导,优化路径变成锯齿状。
解决:训练前做StandardScaler。注意只能用训练集的均值和方差变换测试集,不要在拟合scaler时混入测试集信息。如果你用L1正则化,标准化更重要——否则正则项对不同量纲特征的惩罚不等价,结果会偏爱量纲小的特征。
5.2 样本极度不平衡,截距项疯狂漂移
现象:训练完模型,预测概率全集中在0.01附近,所有样本都被判成多数类。准确率高达95%,但目标类召回率为0。
原因:极大似然在正样本稀有时,最优策略就是把基线概率压到样本均值附近,让大多数样本归多数类,这样总损失最小。这是数学上的正确行为,但业务上没用。
解决:sklearn里用class_weight='balanced',让少数类样本在损失中的权重按比例放大。也可以在预处理时对少数类做SMOTE过采样。评估指标别用准确率,改PR曲线和F1。ROC在极端不平衡下会显得过于乐观——负样本占比大,假正率被稀释,曲线会很漂亮,但实际召回为0。
5.3 完美分离时模型不收敛,LogLoss却不降
现象:训练集上某个特征能完美分开正负样本,梯度下降里w越来越大,但损失已经降到0.01以下,AUC接近1。
原因:数据线性可分时,极大似然估计没有有限解。似然函数在w趋于无穷时才达到最大,优化过程会一直往边界方向推,参数永不安静。
解决:加L2正则化,目标函数会变严格凸,最优解被拉回有限范围。sklearn默认带L2,手写实现要自己加正则项。如果业务要求不罚参数,那就要接受w很大、预测概率趋近0或1的模型,并且后续必须做概率校准,否则输出概率不能当置信度用。
5.4 正则化参数C选错,稀疏特征全被清零
现象:L1正则化后很多特征系数变成0,模型表现反而比不罚时差;或者C调太大时训练集AUC很高,测试集掉得厉害。
原因:C是正则化倒数,C太小正则太强,重要特征被一起缩掉;C太大约等于没正则,直接过拟合。L1对特征量纲也敏感,同一样惩罚在不同量纲特征上力度完全不一样。
解决:用交叉验证在C的对数网格里搜。特征维度上千时优先L1,能自动做特征选择,我在Spark数据分析案例里就靠这一手把3000维特征筛到200维,再切L2精调。维度几百以内直接用L2更稳,没必要引入L1的稀疏化副作用。
5.5 最大熵模型特征爆炸,数据先扛不住
现象:用最大熵模型做多分类时,特征交叉项一多,内存直接爆掉,训练时间指数级上涨。
原因:最大熵模型的特征函数可以自由设计,但参数数量在特征和标签的笛卡尔积下爆炸。几万个特征乘上类别数,参数瞬间到几十万,每轮GIS迭代都要重算模型期望,开销极大。
解决:先用卡方检验或互信息筛选特征,把维度压到几千以内再训练。或者干脆放弃最大熵,改用Logistic回归加正则。最大熵模型的价值更多在NLP的序列标注里,CRF就是它对结构化输出的推广。普通表格数据分析任务,Logistic回归已经能覆盖绝大多数需求,没必要为了「高级」堆交叉特征。
6. 验证Logistic回归的最后一公里:校准曲线与似然比检验
6.1 校准曲线:概率预测得准不准
Logistic回归输出的是概率,但很多团队只拿它排序,然后被业务方打回来:「你说有80%概率,实际哪有这么高。」这是概率校准问题。校准曲线把预测概率分箱,对比每箱内预测均值和真实正样本率:
from sklearn.calibration import calibration_curve import matplotlib.pyplot as plt prob_true, prob_pred = calibration_curve(y_test, prob, n_bins=10) plt.plot(prob_pred, prob_true, marker='o') plt.plot([0, 1], [0, 1], '--', color='gray') plt.xlabel('Mean predicted probability') plt.ylabel('Actual positive rate')n_bins=10代表分10档。点在对角线下方,说明预测概率系统性高估;上方则低估。AUC只看排序能力,校准曲线看概率绝对值,两者不能互相替代。
6.2 似然比检验:确认你加的交互项值不值
在模型里加交互项或新特征后,别只盯着AUC涨了0.002。用似然比检验判断改进是否显著:
import statsmodels.api as sm m1 = sm.Logit(y_train, Xb).fit() m2 = sm.Logit(y_train, Xb_ext).fit() lr_stat = 2 * (m2.llf - m1.llf)lr_stat服从卡方分布,自由度是两个模型参数数之差。p值小于0.05说明新特征值得保留。这个做法比看准确率变化靠谱,因为准确率对概率数值不敏感,可能加了没用的特征恰好改变了阈值划分。
个人教训:早期做模型只看AUC,有一次给业务方交付模型,对方问「你说概率80%,真到80%吗」,我画了校准曲线一看,模型预测0.8的位置实际只有0.6,当场翻车。从那以后,每个Logistic回归项目必须先画校准曲线再做推断。最大熵与Logistic回归的关系也是那次之后才彻底补明白——如果你是半路出家做数据分析,花一个晚上把从最大熵到sigmoid的推导走一遍,绝对值回票价。希望帮到你。
本文还有配套的精品资源,点击获取