Logistic回归全解:从线性模型到分类概率与非线性变换
2026/9/8 2:28:18 网站建设 项目流程

这门课讲到L4,终于从连续值预测切到分类任务了。如果你是第一次接触模式识别和机器学习,这一讲会是个分水岭——很多同学前几讲跟着推公式还觉得轻松,到Logistic回归突然开始犯迷糊,原因很简单:这个算法名字里带着“回归”两个字,干的却是分类的活,而且它牵扯到的损失函数、梯度推导、特征变换,每一个点都能单独出成一道大题。这篇笔记把这一讲讲透:Logistic回归是怎么从线性模型里长出来的、它的损失函数为什么长那样、非线性变换到底在变换什么、以及期末复习时那些反复出现的考点到底应该怎么答。无论你是在刷吴恩达的课,还是在为周志华那本书的课后题头疼,这篇都可以直接拿来当复习提纲用。

1. 从回归到分类:Logistic回归到底解决了什么问题

1.1 线性回归在分类任务上翻车的现场

先看一个最常见的例子:假设肿瘤医院收集了一批病例,特征是肿瘤大小,标签是“良性/恶性”,分别记为0和1。你可能会想,这还不简单,直接用线性回归去拟合这个0/1标签不就行了?实测下来你会发现一个很尴尬的现象:拟合出来的直线,对于特别大的肿瘤尺寸,预测值能飙到1.3甚至2.0,对特别小的尺寸,预测值可能是-0.5。你说这算恶性还是良性?完全没法解释。

有人会说,那我加一个阈值——预测值大于0.5就判为恶性,小于0.5就判为良性,这不就行了吗?问题是线性回归对异常值极其敏感。假设数据里出现一个巨无霸肿瘤,尺寸远超其他样本,最小二乘为了拟合这个点,会把整条直线往下压,导致原来一些恶性样本的预测值低于0.5,直接判错。这不是调参能解决的问题,而是线性回归的本质就是让预测值逼近实数,而你需要的输出是一个“概率”。

另一个更隐蔽的问题:线性回归用来拟合0/1标签时,损失函数是均方误差,但均方误差对分类任务来说并不是一个好的度量。分类错误的后果不应该是“预测值偏离标签的平方差”,而应该是“这个样本被判错了”,这两者的数学性质完全不同。所以,分类任务需要的不是数值拟合,而是概率建模。

1.2 分类问题的本质:估计概率而不是拟合数值

把问题重新定义一下:给定特征x,我们想知道的是P(y=1|x),也就是这个样本属于正类的概率。注意,这个概率天然落在[0,1]区间内。而线性回归给出的 w^T x + b 是一个实数,范围是负无穷到正无穷。所以核心矛盾变成了:怎么把一个实数轴上的值,压到(0,1)区间里,并且保持单调性——线性组合越大,概率越高。

这就是Logistic回归的出发点。它做的事可以拆成两步:第一步,仍然保持线性组合 z = w^T x + b;第二步,套一个sigmoid函数 σ(z) = 1 / (1 + e^{-z}),把z映射到(0,1)。这个函数在z=0时取值0.5,z趋向正无穷时趋近1,z趋向负无穷时趋近0,刚好满足概率的所有性质。

这里需要强调一个关键认知:分类问题的误差度量方式,天然是“0/1损失”——分对就是0,分错就是1。但0/1损失在数学上不可导,梯度下降没法用。所以Logistic回归选择用一种“替代损失”,这就是下一章要讲的交叉熵。理解这条逻辑链很重要,期末如果考“为什么分类不用线性回归”或“为什么损失函数是交叉熵”,你只需要把这条链讲清楚,基本就满分了。

2. Logistic回归的核心数学原理:从对数几率到交叉熵

2.1 Sigmoid函数与对数几率:两个角度推导出同一个模型

先直接给出sigmoid的形式:

σ(z) = 1 / (1 + e^{-z})

其中 z = w^T x + b。模型输出 p = σ(z),我们把它解释为P(y=1|x)的估计值。如果p > 0.5,判为正类;p < 0.5,判为负类。决策边界就是 p = 0.5,即 w^T x + b = 0,这在特征空间里是一条直线(或超平面)。

但为什么一定是sigmoid,而不是别的函数?这里面有一个很漂亮的推导:假设对数几率(log-odds)与特征x是线性关系,也就是

log(p / (1-p)) = w^T x + b

这个式子左边叫“对数几率”,几率(odds)指的是事件发生概率与不发生概率的比值 p/(1-p)。一个事件发生的几率越大,说明它越可能发生。对几率取对数后,取值就是整个实数轴,可以和右边的线性组合完全匹配。把这个式子反解出来:

p / (1-p) = e^{w^T x + b}
p = e^{w^T x + b} / (1 + e^{w^T x + b}) = 1 / (1 + e^{-(w^T x + b)})

正好就是sigmoid函数。所以Logistic回归的名字里虽然有“回归”,但它其实是“对对数几率做线性回归”,本质上是个分类模型。这个考点几乎年年出现: “Logistic回归为什么叫回归?” 标准答法就是这个对数几率推导。

2.2 损失函数:为什么是交叉熵而不是均方误差

模型输出的是一个概率p,真实标签y是0或1。我们希望p尽量贴近y:当y=1时p越大越好,当y=0时p越小越好。把这两种情况统一成一个表达式,就是单样本损失:

L = -[ y * log(p) + (1-y) * log(1-p) ]

这就是二分类交叉熵损失。为什么用log?因为log是单调递增函数,而且当预测完全错误时(例如y=1但p接近0),-log(p)会趋向正无穷,惩罚非常重;当预测正确时惩罚趋近0。这种“错得越离谱、罚得越狠”的性质,正符合分类任务的需求。

那为什么不用均方误差(MSE)呢?这是考试最爱考的一个点。把sigmoid代入MSE,得到的损失函数关于参数w是非凸的,存在多个局部极小值,梯度下降很可能陷进去出不来。而交叉熵配上sigmoid,在数据满足一定条件下是关于w的凸函数,凸函数只有一个全局最小值,梯度下降能可靠收敛。另外,从最大似然的角度看,交叉熵恰好是“伯努利分布假设下的负对数似然”。也就是说,Logistic回归的损失函数是有概率理论基础支撑的,不是随便拍脑袋定的。

2.3 梯度下降与参数更新规则

有了损失函数,接下来就是求梯度、更新参数。对单个样本,令 z = w^T x + b,p = σ(z),可以算出:

∂L/∂w = (p - y) * x
∂L/∂b = p - y

这个结果简洁得让人惊讶。每个样本对梯度的贡献,就是“预测残差(p-y)”乘以该样本的特征向量x。参数更新规则就是:

w ← w - η * (p - y) * x
b ← b - η * (p - y)

其中η是学习率。注意,这个梯度形式里没有出现sigmoid的导数项σ'(z) = σ(z)(1-σ(z))。这正是交叉熵的巧妙之处:如果换用MSE,梯度里会多乘一个σ'(z),而sigmoid两端趋于饱和,σ'(z)接近0,会导致参数几乎不更新,也就是梯度消失。所以“交叉熵+sigmoid”的组合,在数值上远比“MSE+sigmoid”稳定,训练速度也快得多。这是我实际跑实验时的切身体会,一开始没理解这点,换过MSE试了一次,loss曲线直接躺平。

3. 非线性变换:线性模型如何学会“拐弯”

3.1 线性模型的边界限制:从异或问题说起

线性模型的决策边界是超平面,这既是它的简单之处,也是它的天花板。最经典的例子是异或(XOR)问题:四个点(0,0)、(1,1)属于一类,(0,1)、(1,0)属于另一类。你画一条直线试试,无论如何都分不开这两类。另一个例子就是两个同心圆环的分布,内圈和外圈各为一类,线性分类器只能找到一条直线,无论怎么摆都会把两类切得乱七八糟。

这些问题迫使我们去思考:如果原始特征空间里线性不可分,那能不能换一个特征空间,让数据在新的空间里变得线性可分?这就是非线性变换的核心思想。这里有必要提一下Cover定理:在高维空间中,数据被线性可分的概率会随着维度增加而提高。换句话说,特征维度越高,分起来越容易,但代价是什么?下面马上讲。

3.2 多项式特征与基函数展开:具体怎么构造

非线性变换最简单的落地方式就是构造多项式特征。假设原始特征只有两个:x1、x2,那我们把它扩展成:

φ(x) = (1, x1, x2, x1², x1*x2, x2²)

也就是说,从2个特征变成6个特征。在这个6维空间中,我们仍然用线性模型(Logistic回归),但找到的超平面会对应回原始空间的一条曲线。

拿圆环数据举例:内圈和外圈在原始二维空间里是线性不可分的,但只要你构造一个新特征 r² = x1² + x2²,问题一下就简单了——内圈半径小,r²小;外圈半径大,r²大。在“原始特征+新特征”组成的空间里,用一条直线就能分开。这就是非线性变换最直观的威力:把原始空间里的曲线边界,转化成新空间里的直线边界。

更一般地,我们可以用基函数展开(basis function expansion)来构造特征,比如高斯基函数、傅里叶基、样条基等。每个基函数负责捕捉局部或全局的一种形态。这也是“广义线性模型”的思想:先做特征变换φ(x),再把φ(x)喂给线性模型。逻辑上完全自洽,实现起来也简单,只需要在数据预处理阶段加一步PolynomialFeatures。

3.3 维度爆炸与过拟合:非线性变换不是免费午餐

非线性变换听起来很香,但它有一个致命的代价:特征数量会爆炸式增长。如果原始特征有m个,用d次多项式展开,特征数量大约是O(m^d)。假设m=10,d=5,特征数量就能到上千。特征多了,参数也多了,模型就特别容易把训练样本背下来,而不是学到真正的规律——这就是过拟合。

判断是否过拟合有个很实际的方法:看训练集和验证集的准确率差距。训练集98%、验证集70%,基本就是过拟合了。解决方法无非三条路:一是降低多项式次数,别一味加高;二是加正则化,L1能帮你把无关特征的系数压成0,L2能把所有系数整体缩小;三是增加数据量,但数据往往是最难搞的。这里埋个伏笔:后面讲到的核方法(Kernel Method),本质就是“既想做高维变换,又不想显式计算高维特征”的聪明解法,它用核函数直接计算高维空间的内积,绕开了维度爆炸问题。L4这一讲,你先理解线性变换→非线性变换这条逻辑线就够了。

4. Python实操:从零手写到sklearn调参

4.1 数据准备:构造一个线性不可分的例子

理论讲了这么多,不跑代码等于白讲。我经常用sklearn自带的make_circles来演示非线性变换的效果:

import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_circles X, y = make_circles(n_samples=300, factor=0.5, noise=0.05, random_state=42) plt.scatter(X[y == 0, 0], X[y == 0, 1], label='class 0') plt.scatter(X[y == 1, 0], X[y == 1, 1], label='class 1') plt.legend() plt.show()

这个数据长什么样呢?外面的圆是一类,里面的小圆是另一类,肉眼可见地需要一条曲线才能分开。现在直接拿原始特征去训练Logistic回归,看看效果如何。

from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) model = LogisticRegression() model.fit(X_train_scaled, y_train) print("训练集准确率:", model.score(X_train_scaled, y_train)) print("测试集准确率:", model.score(X_test_scaled, y_test))

实测下来,训练集和测试集准确率都在0.5左右,跟瞎猜没区别。这印证了上面的结论:线性模型在原始特征空间里拿这个数据没办法。注意我在这里先做了StandardScaler,这个步骤不是可选项——Logistic回归用梯度下降求解时,特征的尺度如果不一致,梯度更新会来回震荡,收敛速度极慢,后面第5章我们会再聊这个问题。

4.2 手写一个Logistic回归:只有三十行代码

为了让你彻底搞懂内部机制,我用numpy把整个训练过程手写一遍。别怕,核心就四个部分:sigmoid、损失计算、梯度计算、参数更新。

class LogisticRegressionScratch: def __init__(self, lr=0.1, epochs=500): self.lr = lr self.epochs = epochs self.w = None self.b = 0.0 def sigmoid(self, z): return 1 / (1 + np.exp(-z)) def loss(self, X, y): p = self.predict_proba(X) # 加一个极小值防止log(0) return -np.mean(y * np.log(p + 1e-9) + (1 - y) * np.log(1 - p + 1e-9)) def predict_proba(self, X): z = X @ self.w + self.b return self.sigmoid(z) def fit(self, X, y): n_samples, n_features = X.shape self.w = np.zeros(n_features) for epoch in range(self.epochs): p = self.predict_proba(X) # 梯度:见2.3节推导 grad_w = (X.T @ (p - y)) / n_samples grad_b = np.mean(p - y) self.w -= self.lr * grad_w self.b -= self.lr * grad_b if epoch % 100 == 0: print(f"epoch {epoch}, loss = {self.loss(X, y):.4f}") def predict(self, X): return (self.predict_proba(X) >= 0.5).astype(int)

训练过程用我们手写的模型跑一遍:

scratch_model = LogisticRegressionScratch(lr=0.1, epochs=1000) scratch_model.fit(X_train_scaled, y_train) print("手写模型测试集准确率:", np.mean(scratch_model.predict(X_test_scaled) == y_test))

你会发现loss在慢慢下降,但准确率依旧只有0.5左右。这说明什么?说明问题不在优化算法,而在特征空间本身。这就引出了下一步的重头戏——非线性变换。

4.3 加入非线性变换后再训练

现在我们对特征做二阶多项式展开,再喂给同一个模型:

from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2) X_train_poly = poly.fit_transform(X_train_scaled) X_test_poly = poly.transform(X_test_scaled) scratch_model_poly = LogisticRegressionScratch(lr=0.1, epochs=1000) scratch_model_poly.fit(X_train_poly, y_train) print("变换后训练集准确率:", np.mean(scratch_model_poly.predict(X_train_poly) == y_train)) print("变换后测试集准确率:", np.mean(scratch_model_poly.predict(X_test_poly) == y_test))

这次你再看结果,训练集和测试集准确率都能到1.0。需要注意的是,多项式特征会把原始特征的多项式交叉项全部算出来。以degree=2为例:原始特征[x1, x2]会变成[1, x1, x2, x1², x1*x2, x2²],其中1是偏置项对应的常数特征。如果你的模型已经单独学了偏置b,那这个1就有些冗余,但不会影响训练,sklearn内部会处理好。

做完这个实验你会发现,真正让模型“拐弯”的不是Logistic回归本身,而是喂给它的特征。Logistic回归始终是一个线性模型,是特征变换让决策边界从直线变成了曲线。这个认知很重要,因为在很多教材里,Logistic回归被称为“线性分类器”,但实际工程里,大家都会配合特征工程来用。你既不能说它是纯线性,也不能说它是纯非线性,关键看你喂什么特征。

4.4 sklearn版本与关键参数调优

实际项目里当然不需要手写梯度下降,直接用sklearn就好,但参数你得读懂。

from sklearn.pipeline import Pipeline pipe = Pipeline([ ('poly', PolynomialFeatures(degree=2)), ('scaler', StandardScaler()), ('clf', LogisticRegression(C=1.0, penalty='l2', solver='lbfgs', max_iter=1000)) ]) pipe.fit(X_train, y_train) print("pipeline测试集准确率:", pipe.score(X_test, y_test))

Pipeline把特征变换、标准化、分类器串在一起,防止数据泄漏,这是工程里的标准写法。这里重点解释几个参数:

  • C:正则化强度的倒数。C越小,正则化越强,模型越不容易过拟合,但也可能欠拟合;C越大,模型越倾向拟合训练数据,越容易过拟合。我一般按 0.001、0.01、0.1、1、10、100 这个量级去试。
  • penalty:可选l1或l2。l1会把部分特征的系数压成0,相当于自动特征选择;l2会把所有系数均匀缩小,是默认选择。数据特征多且有冗余时,可以试试l1。
  • solver:优化算法的选择。小数据集推荐liblinear;大数据集推荐lbfgs;如果penalty是l1,liblinear和saga都支持,lbfgs不支持。
  • max_iter:最大迭代次数。如果你看到“ConvergenceWarning: Maximum iterations reached”,说明没收敛,两条路:加大max_iter,或者对特征做标准化。多数情况下是后者没做好。

用不同C值去调一遍,你会发现C=0.01时测试集准确率可能是0.98,C=100时可能会掉到0.94,因为模型过拟合了训练集里包含噪声的那个圆环边界。这就是前面讲的“非线性变换不是免费午餐”——变换能力越强,越需要正则化来踩刹车。

5. 常见错误排查与期末高频考点

5.1 训练Loss不降或震荡,问题出在哪

手写模型最大的坑,我挨个踩过,先列一个速查表:

现象可能原因解决方式
loss完全不动学习率太小调大lr,比如从0.01调到0.1或0.5
loss剧烈震荡学习率太大调小lr,或用学习率衰减
效果很差但loss正常没做特征标准化加StandardScaler
loss直接nan特征含有极端值/梯度爆炸标准化 + 减小学习率 + 检查是否有inf
二分类但输出三个值标签传成了稀疏矩阵用y.ravel()或保证y形状为(n_samples,)

有一个我特别想强调的点:学率率的设置。手写模型里我用的是固定学习率,但实际训练中,随着loss逐渐变小,固定学习率可能会导致最后阶段在最优值附近来回震荡。简单做法的调小学习率;高级点的可以用Adam这类自适应优化器,但那是后面优化专题的内容。

另外,如果你发现加非线性变换后loss降得更快了,别高兴太早。高维特征会让模型表达能力变强,但也可能让训练loss降到非常接近0,然后在测试集上崩掉——典型的过拟合。一定要看测试集的表现,不能只看训练loss。

5.2 过拟合怎么判断与处理

判断过拟合我有个非常直观的经验:把训练出的模型系数w打出来,如果某些系数的绝对值大得离谱(比如上千),那大概率过拟合了。因为模型在用很大的系数去强行扭曲决策边界,好把训练集里那些离群点和噪声点也分对。处理手段按优先级排序:

  1. 降低多项式次数。不要一上来就degree=5,先从2、3试起。
  2. 调大C(其实是降低正则化强度?不对——是调小C来增强正则化)。注意方向,别搞反,C是正则化强度的倒数。
  3. 换L1正则化,让模型自动丢弃无关特征。
  4. 增加样本量,或者做数据增强。

这里有张我常用的对照表:

C值正则化强度训练集准确率测试集准确率判断
1001.000.93过拟合
10.990.98合适
0.010.940.94欠拟合

从这个表能看出,正则化太强会压制模型的表达能力,导致训练集都学不好;太弱又会死记硬背。交叉验证就是干这个的,找个验证集调C,别用测试集调参,否则测试集就“脏”了。

5.3 期末高频考点与易错点速查

每到期末,总有同学拿着各种版本的复习资料来问我,其实考点翻来覆去就这些。这里按出现频率整理一份清单:

考点标准答法要点
Logistic回归是回归还是分类分类模型。“Logistic回归”名字来源于对“对数几率”做回归
为什么用sigmoid函数把线性组合映射到(0,1),使其可解释为概率;从对数几率推导自然得出
为什么损失用交叉熵而不用MSEMSE+sigmoid非凸,梯度会乘sigmoid导数,易梯度消失;交叉熵是凸函数,且对应伯努利负对数似然
写出梯度更新公式∂L/∂w = (p-y)x,w ← w - η(p-y)x
决策边界是什么w^T x + b = 0,是一条直线或超平面
非线性变换的作用把原始特征映射到高维空间,让线性模型能处理非线性可分数据
非线性变换的代价特征维度爆炸、过拟合风险,需要正则化控制
二分类如何扩展到多分类OvR(一对多)、OvO(一对一),或softmax回归(多分类的Logistic回归推广)
Logistic回归与线性回归的联系都是广义线性模型;区别在于输出经过sigmoid且损失函数不同

另外有一个非常容易丢分的细节:sigmoid的输出 p 到底是不是真实的概率?准确说,p 是模型对条件概率 P(y=1|x) 的一个估计,但它不一定是“校准”过的概率——就是说,如果模型输出0.7,不代表100个这样的样本里一定有70个是正类。如果想要校准的概率,需要做Platt Scaling之类的事后校准。这个概念很多教材放在高级部分,但试卷里如果考到“Logistic回归输出的概率是否可信”,你要能说出这一层。

我个人在带期末复习时,发现大家最容易栽的坑是:把Logistic回归当成一个黑盒,公式能默写,但一被问“为什么这里用log”就卡住。所以这一讲真的不要跳着看,把第2章的推导自己闭卷推两遍,再把第4章的代码完整跑一遍,比你考前刷十道选择题都管用。这也是为什么我把推导和代码放在一起写——它们本来就是同一件事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询