第四章:从直觉到公式------线性模型的原理、实现与解释
"所有模型都是错的,但有些是有用的。"
------George E.P. Box
而线性模型,正是那个最简单却最有用的起点。
一、为什么从线性模型开始?
在深度学习大行其道的今天,你可能会问:为什么还要学"古老"的线性模型?
答案有三:
-
它是理解机器学习的"最小可行单元"
没有复杂的黑箱,每一步都可解释、可推导、可可视化。
-
它在实践中依然强大
在金融风控、医疗诊断、推荐系统等高可解释性场景中,线性模型仍是首选。
-
它是通往复杂模型的桥梁
逻辑回归 → 神经网络;岭回归 → 正则化思想;特征工程 → 深度学习中的嵌入层。
🎯 本章目标:
- 掌握线性回归与逻辑回归的数学本质;
- 亲手从零实现一个线性模型;
- 理解损失函数、梯度下降、正则化等核心概念;
- 学会解读模型系数,讲出"为什么"。
二、线性回归:用一条直线预测世界
1. 直觉:找一条"最佳拟合线"
假设你想预测房价。你观察到:
- 房子越大,价格越高;
- 但不是严格成正比(有噪声)。
于是你画一条直线,让它尽可能靠近所有数据点------这就是线性回归。

2. 数学表达
对于一个样本 x=[x1,x2,...,xn]\mathbf{x} = [x_1, x_2, ..., x_n]x=[x1,x2,...,xn](如面积、房龄、卧室数),
线性模型预测值为:
y^=w0+w1x1+w2x2+⋯+wnxn \hat{y} = w_0 + w_1 x_1 + w_2 x_2 + \cdots + w_n x_n y^=w0+w1x1+w2x2+⋯+wnxn
或写成向量形式:
y^=w⊤x \hat{y} = \mathbf{w}^\top \mathbf{x} y^=w⊤x
其中:
- w=[w0,w1,...,wn]⊤\mathbf{w} = [w_0, w_1, ..., w_n]^\topw=[w0,w1,...,wn]⊤ 是权重向量 (w0w_0w0 是偏置项);
- x=[1,x1,...,xn]⊤\mathbf{x} = [1, x_1, ..., x_n]^\topx=[1,x1,...,xn]⊤(首项为1,用于容纳偏置)。
💡 关键思想 :模型的学习过程,就是找到最优的 w\mathbf{w}w。
3. 如何定义"最佳"?------损失函数
我们希望预测值 y^i\hat{y}_iy^i 尽可能接近真实值 yiy_iyi。
常用均方误差(MSE)作为损失函数:
L(w)=1m∑i=1m(y^i−yi)2=1m∑i=1m(w⊤xi−yi)2 \mathcal{L}(\mathbf{w}) = \frac{1}{m} \sum_{i=1}^{m} (\hat{y}i - y_i)^2 = \frac{1}{m} \sum{i=1}^{m} (\mathbf{w}^\top \mathbf{x}_i - y_i)^2 L(w)=m1i=1∑m(y^i−yi)2=m1i=1∑m(w⊤xi−yi)2
其中 mmm 是样本数。
✅ 目标 :找到 w∗=argminwL(w)\mathbf{w}^* = \arg\min_{\mathbf{w}} \mathcal{L}(\mathbf{w})w∗=argminwL(w)
4. 求解方法一:解析解(正规方程)
对 MSE 求导并令导数为零,可得闭式解:
w∗=(X⊤X)−1X⊤y \mathbf{w}^* = (\mathbf{X}^\top \mathbf{X})^{-1} \mathbf{X}^\top \mathbf{y} w∗=(X⊤X)−1X⊤y
其中 X\mathbf{X}X 是 m×(n+1)m \times (n+1)m×(n+1) 的设计矩阵(每行是一个样本)。
✅ 优点:一次计算,精确解;
❌ 缺点:当特征数 nnn 很大时,矩阵求逆 O(n3)O(n^3)O(n3) 计算昂贵,且 X⊤X\mathbf{X}^\top \mathbf{X}X⊤X 可能不可逆。
5. 求解方法二:梯度下降(通用优化框架)
由于解析解不适用于大规模数据,我们采用迭代优化:
- 随机初始化 w\mathbf{w}w;
- 计算损失函数对 w\mathbf{w}w 的梯度;
- 沿梯度反方向更新 w\mathbf{w}w;
- 重复直到收敛。
梯度计算:
∇wL=2mX⊤(Xw−y) \nabla_{\mathbf{w}} \mathcal{L} = \frac{2}{m} \mathbf{X}^\top (\mathbf{X} \mathbf{w} - \mathbf{y}) ∇wL=m2X⊤(Xw−y)
更新规则:
w:=w−α∇wL \mathbf{w} := \mathbf{w} - \alpha \nabla_{\mathbf{w}} \mathcal{L} w:=w−α∇wL
其中 α\alphaα 是学习率(learning rate)。
🔑 梯度下降是几乎所有现代机器学习算法的基石,包括神经网络。
三、动手实现:从零写一个线性回归
我们将用 NumPy 实现带梯度下降的线性回归。
python
import numpy as np
import matplotlib.pyplot as plt
class LinearRegression:
def __init__(self, learning_rate=0.01, n_iterations=1000):
self.lr = learning_rate
self.n_iters = n_iterations
self.weights = None
self.bias = None
self.losses = []
def fit(self, X, y):
n_samples, n_features = X.shape
# 初始化参数
self.weights = np.zeros(n_features)
self.bias = 0
# 梯度下降
for _ in range(self.n_iters):
# 前向传播:预测
y_pred = np.dot(X, self.weights) + self.bias
# 计算损失(MSE)
loss = np.mean((y_pred - y) ** 2)
self.losses.append(loss)
# 计算梯度
dw = (1 / n_samples) * np.dot(X.T, (y_pred - y))
db = (1 / n_samples) * np.sum(y_pred - y)
# 更新参数
self.weights -= self.lr * dw
self.bias -= self.lr * db
def predict(self, X):
return np.dot(X, self.weights) + self.bias
# 测试:生成模拟数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X.flatten() + np.random.randn(100) # y = 4 + 3x + noise
# 训练模型
model = LinearRegression(learning_rate=0.1, n_iterations=1000)
model.fit(X, y)
# 预测
y_pred = model.predict(X)
# 可视化
plt.scatter(X, y, alpha=0.6, label='Data')
plt.plot(X, y_pred, color='red', label=f'Predicted: y = {model.bias:.2f} + {model.weights[0]:.2f}x')
plt.legend()
plt.title('Linear Regression from Scratch')
plt.show()
# 查看损失变化
plt.plot(model.losses)
plt.title('Loss over Iterations')
plt.xlabel('Iteration')
plt.ylabel('MSE')
plt.show()
✅ 运行结果将显示:
- 拟合直线接近真实关系(斜率≈3,截距≈4);
- 损失随迭代逐渐下降并收敛。
四、逻辑回归:用线性模型做分类
❗ 注意:尽管名字叫"回归",逻辑回归是分类算法!
1. 问题:线性回归不能直接用于分类
若用线性回归预测"是否患糖尿病"(0 或 1),输出可能是 -0.5 或 2.3------这没有意义。
我们需要一个输出在 [0,1][0,1][0,1] 区间的函数,表示"属于正类的概率"。
2. Sigmoid 函数:引入非线性
定义 Sigmoid 函数:
σ(z)=11+e−z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
性质:
- 当 z→+∞z \to +\inftyz→+∞,σ(z)→1\sigma(z) \to 1σ(z)→1;
- 当 z→−∞z \to -\inftyz→−∞,σ(z)→0\sigma(z) \to 0σ(z)→0;
- σ(0)=0.5\sigma(0) = 0.5σ(0)=0.5。
于是,逻辑回归模型为:
P(y=1∣x)=σ(w⊤x)=11+e−(w⊤x) P(y=1 \mid \mathbf{x}) = \sigma(\mathbf{w}^\top \mathbf{x}) = \frac{1}{1 + e^{-(\mathbf{w}^\top \mathbf{x})}} P(y=1∣x)=σ(w⊤x)=1+e−(w⊤x)1
3. 损失函数:交叉熵(Cross-Entropy)
不能用 MSE!因为 Sigmoid + MSE 会导致非凸优化问题(多个局部最优)。
正确选择是对数似然损失(即交叉熵):
L(w)=−1m∑i=1m[yilog(y^i)+(1−yi)log(1−y^i)] \mathcal{L}(\mathbf{w}) = -\frac{1}{m} \sum_{i=1}^{m} \left[ y_i \log(\hat{y}_i) + (1 - y_i) \log(1 - \hat{y}_i) \right] L(w)=−m1i=1∑m[yilog(y^i)+(1−yi)log(1−y^i)]
其中 y^i=σ(w⊤xi)\hat{y}_i = \sigma(\mathbf{w}^\top \mathbf{x}_i)y^i=σ(w⊤xi)。
✅ 该损失函数是凸的,梯度下降可找到全局最优。
4. 梯度形式(惊人地简洁!)
尽管损失函数复杂,其梯度却与线性回归形式相同:
∇wL=1mX⊤(y^−y) \nabla_{\mathbf{w}} \mathcal{L} = \frac{1}{m} \mathbf{X}^\top (\hat{\mathbf{y}} - \mathbf{y}) ∇wL=m1X⊤(y^−y)
这是巧合吗?不,这是指数族分布的优美性质。
五、使用 scikit-learn 快速建模
实际项目中,我们使用成熟库:
python
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, accuracy_score, classification_report
from sklearn.datasets import load_boston, load_iris
# 回归示例:波士顿房价
boston = load_boston()
X, y = boston.data, boston.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
lr = LinearRegression()
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)
print("RMSE:", np.sqrt(mean_squared_error(y_test, y_pred)))
# 分类示例:鸢尾花
iris = load_iris()
X, y = iris.data, (iris.target == 0).astype(int) # 二分类:Setosa vs others
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
y_pred = log_reg.predict(X_test)
print("Accuracy:", accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred))
六、解读模型:系数告诉你"为什么"
线性模型的最大优势:可解释性。
以房价预测为例:
| 特征 | 系数(权重) | 解读 |
|---|---|---|
| 房屋面积(㎡) | +3.2 | 面积每增加1㎡,房价平均上涨3.2万元 |
| 房龄(年) | -0.5 | 房龄每增加1年,房价平均下降0.5万元 |
| 是否近地铁 | +15.0 | 近地铁的房子贵15万元 |
🔍 注意:系数大小受特征尺度影响!务必先标准化,再比较重要性。
特征重要性可视化
python
import pandas as pd
# 假设已训练好模型 lr
feature_names = boston.feature_names
coef_df = pd.DataFrame({
'feature': feature_names,
'coef': lr.coef_
}).sort_values('coef', key=abs, ascending=False)
plt.figure(figsize=(8, 6))
plt.barh(coef_df['feature'], coef_df['coef'])
plt.title('Linear Regression Coefficients (Feature Importance)')
plt.xlabel('Coefficient Value')
plt.show()
七、过拟合与正则化:让模型更稳健
当特征很多或数据很少时,线性模型也会过拟合(在训练集上完美,测试集上差)。
解决方案:正则化(Regularization)
在损失函数中加入惩罚项,限制权重大小。
1. 岭回归(Ridge Regression)--- L2 正则化
Lridge=MSE+α∑j=1nwj2 \mathcal{L}{\text{ridge}} = \text{MSE} + \alpha \sum{j=1}^{n} w_j^2 Lridge=MSE+αj=1∑nwj2
- 惩罚大权重,但不会让权重变为0;
- 适用于所有特征都可能有用,但希望平滑的情况。
2. Lasso 回归 --- L1 正则化
Llasso=MSE+α∑j=1n∣wj∣ \mathcal{L}{\text{lasso}} = \text{MSE} + \alpha \sum{j=1}^{n} |w_j| Llasso=MSE+αj=1∑n∣wj∣
- 可将部分权重压缩至0 ,实现自动特征选择;
- 适用于高维稀疏数据(如文本)。
📌 参数 α\alphaα 控制正则化强度:
- α=0\alpha = 0α=0 → 无正则化(普通线性回归);
- α→∞\alpha \to \inftyα→∞ → 所有权重趋近0。
python
from sklearn.linear_model import Ridge, Lasso
ridge = Ridge(alpha=1.0)
lasso = Lasso(alpha=0.1)
ridge.fit(X_train, y_train)
lasso.fit(X_train, y_train)
print("Ridge non-zero coeffs:", np.sum(ridge.coef_ != 0)) # 通常 = 总特征数
print("Lasso non-zero coeffs:", np.sum(lasso.coef_ != 0)) # 可能 < 总特征数
八、线性模型的局限与超越
局限性
- 只能捕捉线性关系 :无法拟合 y=x2y = x^2y=x2 这类曲线;
- 对异常值敏感:MSE 会放大大误差的影响;
- 特征需人工构造:无法自动发现"面积 × 房龄"这类交互项。
如何超越?
- 特征工程 :手动添加多项式特征(
PolynomialFeatures); - 广义加性模型(GAM):允许每个特征有非线性函数;
- 树模型或神经网络:自动学习非线性与交互。
但请记住:在满足线性假设的场景下,线性模型往往是最优解------因为它稳定、快速、可解释。
九、结语:简单,是一种高级的智慧
线性模型没有炫目的准确率,没有复杂的架构,但它教会我们:
- 模型的目标不是拟合数据,而是理解数据;
- 可解释性有时比精度更重要;
- 最强大的工具,往往藏在最简单的形式里。
在下一篇文章中,我们将进入决策树与集成方法的世界------那里有更强的非线性能力,也有新的可解释性挑战。
但在那之前,请确保你真正掌握了线性模型。因为所有复杂模型,都是对"线性+非线性"的不同组合。
行动建议
- 用真实数据集(如波士顿房价、泰坦尼克号)训练线性/逻辑回归;
- 尝试添加多项式特征,观察是否提升性能;
- 对比 Ridge 与 Lasso 的系数,理解 L1 的稀疏性;
- 向非技术人员解释你的模型:"为什么这个人被预测为高风险?"
真正的掌握,不在于你能写多少代码,而在于你能讲清多少道理。
全文约 3,800 字(不含代码)|总字符数约 11,000
✅ 现在所有公式均已使用 $...$(行内)或 $$...$$(块级)格式 ,可在支持 MathJax/KaTeX 的 Markdown 渲染器中正常显示。
如您需要纯文本版本(无公式)、HTML 版本,或转换为 Jupyter Notebook,也可以告诉我!