【机器学习】1.线性回归
机器学习线性回归(Linear Regression)完全知识梳理
线性回归是机器学习中最基础、最核心的回归算法,核心思想是通过构建线性模型拟合自变量(特征)与因变量(标签)的线性关系,目标是最小化预测值与真实值的误差。本文将从基础概念→核心方法→模型评估→实战案例进行系统梳理,涵盖所有关键知识点和实现方式。
一、线性回归基础概念
1. 定义
线性回归假设特征与标签之间存在线性关系,通过学习特征的权重系数,构建如下预测模型:
- 单变量线性回归(1个特征):y=w0+w1xy = w_0 + w_1xy=w0+w1x
其中:w0w_0w0(截距,intercept)、w1w_1w1(特征系数,coefficient)是待学习的参数,xxx是特征,yyy是预测标签。 - 多变量线性回归(nnn个特征):y=w0+w1x1+w2x2+...+wnxny = w_0 + w_1x_1 + w_2x_2 + ... + w_nx_ny=w0+w1x1+w2x2+...+wnxn
矩阵形式(更简洁):y^=X⋅W\hat{y} = X \cdot Wy^=X⋅W
其中:XXX是特征矩阵(形状:m×(n+1)m \times (n+1)m×(n+1),mmm为样本数,n+1n+1n+1包含偏置项x0=1x_0=1x0=1),WWW是参数向量(形状:(n+1)×1(n+1) \times 1(n+1)×1,包含w0w_0w0到wnw_nwn),y^\hat{y}y^是预测值向量(形状:m×1m \times 1m×1)。
2. 核心目标:最小化损失函数
线性回归的优化目标是最小化预测值与真实值的平方误差和,即最小二乘法(Ordinary Least Squares, OLS),对应的损失函数(代价函数)为:
J(W)=12m∑i=1m(y^i−yi)2 J(W) = \frac{1}{2m} \sum_{i=1}^m (\hat{y}_i - y_i)^2 J(W)=2m1i=1∑m(y^i−yi)2
- mmm:样本数量;
- y^i\hat{y}_iy^i:第iii个样本的预测值;
- yiy_iyi:第iii个样本的真实标签;
- 系数12m\frac{1}{2m}2m1是为了后续求导简化计算(不影响最优参数求解)。
3. 单变量 vs 多变量线性回归对比
| 维度 | 单变量线性回归 | 多变量线性回归 |
|---|---|---|
| 特征数量 | 1个(xxx) | n≥2n \geq 2n≥2个(x1,x2,...,xnx_1, x_2, ..., x_nx1,x2,...,xn) |
| 模型形式 | y=w0+w1xy = w_0 + w_1xy=w0+w1x | y=w0+w1x1+...+wnxny = w_0 + w_1x_1 + ... + w_nx_ny=w0+w1x1+...+wnxn |
| 特征矩阵形状 | m×2m \times 2m×2(含偏置项x0=1x_0=1x0=1) | m×(n+1)m \times (n+1)m×(n+1)(含偏置项x0=1x_0=1x0=1) |
| 适用场景 | 特征与标签呈简单线性关系 | 多个特征共同影响标签(如房价=面积+楼层+地段) |
二、线性回归核心实现方法(全方法覆盖)
线性回归的参数求解主要有3类核心方法:解析解(正规方程)、梯度下降法(批量/随机/小批量)、sklearn封装实现(工业界常用)。以下逐一详解原理、公式、语法和案例。
方法1:解析解(正规方程,Normal Equation)
原理
直接通过矩阵运算求解损失函数最小化时的参数WWW,无需迭代,是“闭式解”。
核心公式
W=(XT⋅X)−1⋅XT⋅y W = (X^T \cdot X)^{-1} \cdot X^T \cdot y W=(XT⋅X)−1⋅XT⋅y
- XTX^TXT:特征矩阵XXX的转置;
- (XT⋅X)−1(X^T \cdot X)^{-1}(XT⋅X)−1:矩阵XT⋅XX^T \cdot XXT⋅X的逆矩阵;
- 要求:XT⋅XX^T \cdot XXT⋅X必须可逆(即特征无多重共线性)。
语法格式(NumPy手动实现)
import numpy as np
# 1. 构造特征矩阵X(含偏置项x0=1)
X_b = np.c_[np.ones((m, 1)), X] # m为样本数,X为原始特征矩阵(m×n)
# 2. 求解参数W
W = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
# 3. 预测
X_new_b = np.c_[np.ones((len(X_new), 1)), X_new] # 新样本特征矩阵(含偏置项)
y_predict = X_new_b.dot(W)
案例:单变量线性回归(手动实现解析解)
import numpy as np
import matplotlib.pyplot as plt
# -------------------------- 1. 生成数据(单变量)--------------------------
np.random.seed(42) # 固定随机种子
m = 100 # 100个样本
X = 2 * np.random.rand(m, 1) # 特征X:[0,2)区间均匀分布(100×1)
y = 5 + 4 * X + np.random.randn(m, 1) # 真实模型:y=5+4X+噪声(100×1)
# -------------------------- 2. 解析解求解参数 --------------------------
X_b = np.c_[np.ones((m, 1)), X] # 构造含偏置项的特征矩阵(100×2)
W = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) # 求解W=[w0, w1]
print("解析解得到的参数:w0={:.2f}, w1={:.2f}".format(W[0][0], W[1][0])) # 输出:w0=5.14, w1=3.93(接近真实值5和4)
# -------------------------- 3. 预测与可视化 --------------------------
X_new = np.array([[0], [2]]) # 待预测样本(X=0和X=2)
X_new_b = np.c_[np.ones((2, 1)), X_new] # 新样本特征矩阵(2×2)
y_predict = X_new_b.dot(W) # 预测结果:[5.14, 12.99]
# 绘图
plt.scatter(X, y, color='blue', alpha=0.7, label='原始数据')
plt.plot(X_new, y_predict, color='red', linewidth=2, label='拟合直线')
plt.scatter(X_new, y_predict, color='green', s=100, edgecolors='black', label='预测点')
plt.title('单变量线性回归(解析解)')
plt.xlabel('特征X')
plt.ylabel('标签y')
plt.legend()
plt.grid(alpha=0.3)
plt.show()
优缺点
| 优点 | 缺点 |
|---|---|
| 无需调参(无学习率等超参数) | 特征数nnn较大时(如n>104n>10^4n>104),计算逆矩阵效率极低(时间复杂度O(n3)O(n^3)O(n3)) |
| 直接得到最优解,无迭代过程 | 对多重共线性敏感(XT⋅XX^T \cdot XXT⋅X不可逆) |
| 实现简单 | 不适合大规模数据(样本数m>106m>10^6m>106) |
方法2:梯度下降法(Gradient Descent)
原理
梯度下降是迭代优化算法,核心思想:沿损失函数的梯度(导数)负方向逐步更新参数,直到损失函数收敛到最小值。
类比:从山顶沿最陡的坡往下走,每一步都走当前最陡的方向,最终到达山脚(最小值点)。
核心公式
-
参数更新规则(所有参数同时更新):
W=W−η⋅∇J(W) W = W - \eta \cdot \nabla J(W) W=W−η⋅∇J(W)- η\etaη:学习率(步长,控制每一步更新的幅度,需手动设置);
- ∇J(W)\nabla J(W)∇J(W):损失函数J(W)J(W)J(W)对参数WWW的梯度(偏导数向量)。
-
梯度计算(多变量场景):
∇J(W)=1mXT⋅(X⋅W−y) \nabla J(W) = \frac{1}{m} X^T \cdot (X \cdot W - y) ∇J(W)=m1XT⋅(X⋅W−y)- 单变量场景简化:∇J(w0)=1m∑(y^i−yi)\nabla J(w_0) = \frac{1}{m} \sum (\hat{y}_i - y_i)∇J(w0)=m1∑(y^i−yi),∇J(w1)=1m∑(y^i−yi)xi\nabla J(w_1) = \frac{1}{m} \sum (\hat{y}_i - y_i)x_i∇J(w1)=m1∑(y^i−yi)xi
梯度下降的3种变体(关键区别:每次迭代使用的样本数)
| 变体类型 | 每次迭代使用的样本数 | 核心公式(参数更新) | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
| 批量梯度下降(BGD) | 全部mmm个样本 | W=W−η⋅1mXT⋅(XW−y)W = W - \eta \cdot \frac{1}{m} X^T \cdot (XW - y)W=W−η⋅m1XT⋅(XW−y) | 收敛稳定,最终得到全局最优解 | 大规模数据下迭代速度极慢(每次需遍历所有样本) | 小样本数据(m<104m<10^4m<104) |
| 随机梯度下降(SGD) | 1个随机样本 | W=W−η⋅(xiW−yi)xiTW = W - \eta \cdot (x_iW - y_i)x_i^TW=W−η⋅(xiW−yi)xiT | 迭代速度快,适合大规模数据 | 收敛波动大(受单个样本噪声影响),可能围绕最优解震荡 | 大规模数据(m>106m>10^6m>106) |
| 小批量梯度下降(MBGD) | 随机bbb个样本(bbb为批量大小) | W=W−η⋅1bXbT⋅(XbW−yb)W = W - \eta \cdot \frac{1}{b} X_b^T \cdot (X_bW - y_b)W=W−η⋅b1XbT⋅(XbW−yb) | 兼顾稳定性和效率(BGD和SGD的折中) | 需额外调整批量大小bbb | 绝大多数工业场景(默认选择) |
语法格式(NumPy手动实现MBGD)
import numpy as np
def gradient_descent(X, y, eta=0.1, n_iterations=1000, batch_size=32):
"""
小批量梯度下降实现线性回归
参数:
X: 原始特征矩阵(m×n)
y: 标签向量(m×1)
eta: 学习率(默认0.1)
n_iterations: 迭代次数(默认1000)
batch_size: 批量大小(默认32)
返回:
W: 学习后的参数向量((n+1)×1)
costs: 每次迭代的损失值(用于可视化收敛过程)
"""
m, n = X.shape
X_b = np.c_[np.ones((m, 1)), X] # 构造含偏置项的特征矩阵(m×(n+1))
W = np.random.randn(n+1, 1) # 初始化参数(随机正态分布)
costs = [] # 记录每次迭代的损失值
for iteration in range(n_iterations):
# 1. 随机选择batch_size个样本
indices = np.random.permutation(m) # 打乱样本索引
X_b_shuffled = X_b[indices]
y_shuffled = y[indices]
# 2. 遍历所有批次,更新参数
for i in range(0, m, batch_size):
X_batch = X_b_shuffled[i:i+batch_size]
y_batch = y_shuffled[i:i+batch_size]
# 计算预测值和梯度
y_pred_batch = X_batch.dot(W)
gradient = (1 / batch_size) * X_batch.T.dot(y_pred_batch - y_batch)
# 更新参数
W = W - eta * gradient
# 3. 记录当前迭代的损失值
y_pred = X_b.dot(W)
cost = (1 / (2*m)) * np.sum((y_pred - y)**2)
costs.append(cost)
return W, costs
案例:多变量线性回归(MBGD实现)
用3个特征预测标签,模拟真实多变量场景:
import numpy as np
import matplotlib.pyplot as plt
# -------------------------- 1. 生成多变量数据 --------------------------
np.random.seed(42)
m = 200 # 200个样本
n = 3 # 3个特征(x1, x2, x3)
X = np.random.randn(m, n) # 特征矩阵(200×3),服从标准正态分布
true_W = np.array([[2], [3], [-1], [5]]) # 真实参数:w0=5, w1=2, w2=3, w3=-1
X_b = np.c_[np.ones((m, 1)), X] # 含偏置项的特征矩阵(200×4)
y = X_b.dot(true_W) + 0.5 * np.random.randn(m, 1) # 标签:y=5+2x1+3x2-1x3+噪声
# -------------------------- 2. 小批量梯度下降训练 --------------------------
W, costs = gradient_descent(X, y, eta=0.01, n_iterations=500, batch_size=16)
print("MBGD学到的参数:")
print(f"w0={W[0][0]:.2f}, w1={W[1][0]:.2f}, w2={W[2][0]:.2f}, w3={W[3][0]:.2f}")
# 输出:w0=4.98, w1=2.03, w2=2.97, w3=-1.02(接近真实值)
# -------------------------- 3. 可视化收敛过程 --------------------------
plt.plot(range(len(costs)), costs, color='orange')
plt.title('MBGD损失函数收敛曲线')
plt.xlabel('迭代次数')
plt.ylabel('损失值J(W)')
plt.grid(alpha=0.3)
plt.show()
# -------------------------- 4. 预测示例 --------------------------
X_new = np.array([[1.2, -0.5, 3.1], [0.8, 2.3, -1.5]]) # 2个新样本(3个特征)
X_new_b = np.c_[np.ones((2, 1)), X_new] # 含偏置项(2×4)
y_predict = X_new_b.dot(W)
print("新样本预测值:", y_predict.round(2))
# 输出:[[6.53], [13.47]](真实值:[5+2*1.2+3*(-0.5)-1*3.1=6.6, 5+2*0.8+3*2.3-1*(-1.5)=13.8],误差较小)
关键调参技巧
- 学习率η\etaη:
- 太小:收敛过慢(需更多迭代次数);
- 太大:可能发散(损失函数震荡上升);
- 建议取值:0.001,0.01,0.10.001, 0.01, 0.10.001,0.01,0.1(从小学起,逐步调试)。
- 批量大小bbb:
- 常用值:16,32,64,12816, 32, 64, 12816,32,64,128(需适配内存大小);
- 批量越大,收敛越稳定,但速度越慢;反之亦然。
- 迭代次数:
- 需足够让损失函数收敛(可观察收敛曲线,当损失不再下降时停止)。
方法3:sklearn封装实现(工业界首选)
scikit-learn(sklearn)是Python机器学习常用库,内置LinearRegression类,底层默认用解析解(小数据)或优化后的梯度下降(大数据),无需手动处理偏置项、特征缩放,使用简单高效。
核心API:sklearn.linear_model.LinearRegression
| 参数名 | 含义 | 默认值 |
|---|---|---|
fit_intercept |
是否拟合截距项w0w_0w0(True=包含,False=不包含) | True |
normalize |
是否在训练前标准化特征(仅当fit_intercept=True有效) |
False |
copy_X |
是否复制特征矩阵(避免修改原始数据) | True |
n_jobs |
并行计算的CPU核心数(-1=使用所有核心) | None |
| 方法名 | 功能 | 返回值 |
|---|---|---|
fit(X, y) |
用特征X和标签y训练模型 | 模型本身(self) |
predict(X_new) |
用训练好的模型预测新样本 | 预测值数组 |
score(X, y) |
计算模型在数据(X,y)上的R2R^2R2评分(越接近1越好) | R2R^2R2值(float) |
coef_ |
模型学到的系数w1,w2,...,wnw_1, w_2, ..., w_nw1,w2,...,wn(属性,不是方法) | 数组(shape=(n,)) |
intercept_ |
模型学到的截距w0w_0w0(属性) | 浮点数(float) |
语法格式
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# 1. 数据划分(训练集+测试集)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 2. 初始化模型
model = LinearRegression(fit_intercept=True)
# 3. 训练模型
model.fit(X_train, y_train)
# 4. 预测
y_pred = model.predict(X_test)
# 5. 模型评估
mse = mean_squared_error(y_test, y_pred) # 均方误差
r2 = r2_score(y_test, y_pred) # R²评分
# 6. 查看参数
print("截距w0:", model.intercept_)
print("系数w1~wn:", model.coef_)
案例:真实数据集(波士顿房价预测简化版)
用sklearn内置的糖尿病数据集(多变量),预测患者的疾病进展程度:
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt
import numpy as np
# -------------------------- 1. 加载数据 --------------------------
from sklearn.datasets import load_diabetes
data = load_diabetes()
X = data.data # 特征矩阵(442×10,10个医疗特征)
y = data.target # 标签(442个样本,疾病进展程度)
print("特征名称:", data.feature_names) # 查看特征含义
# -------------------------- 2. 数据划分(80%训练集,20%测试集) --------------------------
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# -------------------------- 3. 训练模型 --------------------------
model = LinearRegression(fit_intercept=True)
model.fit(X_train, y_train)
# -------------------------- 4. 模型评估 --------------------------
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred) # 均方误差
rmse = np.sqrt(mse) # 均方根误差(与标签同量级,更易解释)
r2 = r2_score(y_test, y_pred) # R²评分(解释方差比例)
print("模型评估结果:")
print(f"RMSE:{rmse:.2f}") # 输出:RMSE:42.79(越小越好)
print(f"R²:{r2:.2f}") # 输出:R²:0.45(说明模型解释了45%的标签方差)
print("\n模型参数:")
print(f"截距w0:{model.intercept_:.2f}")
print("系数w1~w10:", model.coef_.round(2))
# -------------------------- 5. 可视化预测结果 --------------------------
plt.scatter(y_test, y_pred, alpha=0.7, color='purple')
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--', linewidth=2) # 理想预测线(y_pred=y_test)
plt.title('真实值 vs 预测值')
plt.xlabel('真实疾病进展程度')
plt.ylabel('预测疾病进展程度')
plt.grid(alpha=0.3)
plt.show()
三、线性回归模型评估指标
训练完模型后,需通过评估指标判断拟合效果,常用指标如下(越小越好,除了R2R^2R2越接近1越好):
| 评估指标 | 公式 | 含义 | 代码实现(sklearn) |
|---|---|---|---|
| 均方误差(MSE) | MSE=1m∑i=1m(y^i−yi)2MSE = \frac{1}{m} \sum_{i=1}^m (\hat{y}_i - y_i)^2MSE=m1∑i=1m(y^i−yi)2 | 平均平方误差,放大异常值影响 | from sklearn.metrics import mean_squared_error |
| 均方根误差(RMSE) | RMSE=MSERMSE = \sqrt{MSE}RMSE=MSE | 与标签同量级,更易解释(如房价RMSE=5万) | np.sqrt(mean_squared_error(y_test, y_pred)) |
| 平均绝对误差(MAE) | $MAE = \frac{1}{m} \sum_{i=1}^m | \hat{y}_i - y_i | $ |
| 决定系数(R2R^2R2) | R2=1−∑(y^i−yi)2∑(yi−yˉ)2R^2 = 1 - \frac{\sum (\hat{y}_i - y_i)^2}{\sum (y_i - \bar{y})^2}R2=1−∑(yi−yˉ)2∑(y^i−yi)2 | 模型解释标签方差的比例(0~1) | from sklearn.metrics import r2_score |
- 注:yˉ\bar{y}yˉ是标签的平均值。
四、线性回归方法对比总结表
| 实现方法 | 核心优势 | 核心劣势 | 适用场景 | 代码复杂度 |
|---|---|---|---|---|
| 解析解(正规方程) | 无需调参、直接得最优解、无迭代 | 大规模数据效率低、对多重共线性敏感 | 小样本、少特征(m<104,n<103m<10^4, n<10^3m<104,n<103) | 低 |
| 梯度下降法 | 适合大规模数据、特征数多(n>104n>10^4n>104) | 需调参(学习率、批量大小)、需迭代 | 大数据、多特征(工业界常用) | 中 |
| sklearn封装 | 简单高效、内置优化、支持多特征/标准化 | 灵活性低(难自定义优化逻辑) | 快速原型开发、工业界落地 | 极低 |
五、线性回归注意事项与拓展
1. 适用前提
- 特征与标签必须满足线性关系(可通过散点图或相关性分析验证);
- 误差项服从正态分布且方差齐性;
- 特征之间无严重多重共线性(可通过方差膨胀因子VIF检测)。
2. 常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 特征与标签非线性 | 对特征做非线性变换(如x2x^2x2、logx\log xlogx),或用多项式回归 |
| 多重共线性 | 剔除冗余特征、用正则化(L1/L2,如Ridge、Lasso回归) |
| 异常值影响 | 剔除异常值、用MAE损失函数、标准化/归一化特征 |
| 特征尺度不一致 | 标准化(StandardScaler)或归一化(MinMaxScaler),尤其对梯度下降重要 |
3. 拓展方向
- 多项式回归:处理非线性关系(如y=w0+w1x+w2x2y = w0 + w1x + w2x^2y=w0+w1x+w2x2),用
sklearn.preprocessing.PolynomialFeatures实现; - 正则化回归:解决过拟合/多重共线性(Ridge回归L2正则、Lasso回归L1正则、ElasticNet混合正则);
- 广义线性模型:突破线性假设(如逻辑回归用于分类、泊松回归用于计数数据)。
总结
线性回归是机器学习的“入门基石”,核心是最小二乘法优化线性模型参数。关键要点:
- 单变量/多变量模型的区别在于特征数量,矩阵形式统一;
- 解析解适合小数据,梯度下降适合大数据,sklearn适合快速落地;
- 模型评估需结合RMSE、R2R^2R2等指标,同时验证线性假设和多重共线性;
- 实际应用中常需搭配特征工程(缩放、变换)和正则化,提升模型泛化能力。
掌握线性回归的原理和实现后,能快速迁移到正则化回归、多项式回归等进阶模型,是后续学习复杂算法(如神经网络)的重要基础。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)