线性回归算法
机器学习专题 · 掌握线性回归的完整理论与实现
专题:Python机器学习系统学习
关键词:Python, 机器学习, 线性回归, 最小二乘法, 梯度下降, Ridge回归, Lasso, R², 正则化
一、线性回归概述
线性回归(Linear Regression)是监督学习中最基础也是最重要的回归算法之一。它通过建立一个线性模型来描述自变量(特征)与因变量(目标值)之间的线性关系,被广泛应用于预测、趋势分析、因果关系推断等领域。
与分类问题不同,回归任务预测的是连续值。例如预测房价(如50万、80万)、气温(如25°C、30°C)、销售额等,这些都是回归问题。线性回归的核心思想是:找到一条最佳拟合直线(或超平面),使得所有样本点到这条直线的距离之和最小。
线性回归的通用假设函数形式为:h(x) = wTx + b,其中w是权重向量(参数),b是偏置项,x是输入特征向量。这个看似简单的公式背后蕴含着丰富的统计学和优化理论,是理解更复杂模型(如逻辑回归、神经网络等)的重要基础。
二、一元线性回归
2.1 模型定义
一元线性回归是最简单的形式,只包含一个自变量x和一个因变量y,模型表达式为:y = wx + b。其中w是斜率(权重),b是截距(偏置)。我们的目标是找到最优的w和b,使得模型对训练数据的预测误差最小。
2.2 最小二乘法
最小二乘法(Ordinary Least Squares, OLS)是求解线性回归参数的经典方法。其核心思想是最小化所有样本的预测值与真实值之间的平方误差之和。代价函数(损失函数)为均方误差(Mean Squared Error, MSE):
J(w, b) = (1/2m) * Σ(h(xi) - yi)2
其中m是样本数量,h(xi) = wxi + b是第i个样本的预测值。系数1/2是为了后续求导时抵消系数2,使表达式更简洁。
2.3 梯度下降求解
梯度下降(Gradient Descent)是一种迭代优化算法,通过沿损失函数梯度的反方向更新参数,逐步逼近最小值。参数更新公式如下:
w := w - α * (1/m) * Σ(h(xi) - yi) * xi
b := b - α * (1/m) * Σ(h(xi) - yi)
其中α是学习率(learning rate),控制每一步更新的步长。学习率的选择至关重要:过大可能导致震荡不收敛,过小则收敛速度太慢。
2.4 Python手动实现
下面是一元线性回归的纯Python手动实现,不依赖任何机器学习库:
import numpy as np
class LinearRegressionManual:
"""一元线性回归手动实现"""
def __init__(self, lr=0.01, epochs=1000):
self.lr = lr # 学习率
self.epochs = epochs # 迭代次数
self.w = 0.0 # 权重初始化
self.b = 0.0 # 偏置初始化
def fit(self, X, y):
n = len(X)
for _ in range(self.epochs):
y_pred = self.w * X + self.b
dw = (1/n) * np.sum((y_pred - y) * X)
db = (1/n) * np.sum(y_pred - y)
self.w -= self.lr * dw
self.b -= self.lr * db
def predict(self, X):
return self.w * X + self.b
# 示例数据
X = np.array([1, 2, 3, 4, 5])
y = np.array([2, 4, 5, 4, 6])
model = LinearRegressionManual(lr=0.01, epochs=1000)
model.fit(X, y)
print(f"w={model.w:.4f}, b={model.b:.4f}")
# 预测
print(model.predict(np.array([6])))
2.5 scikit-learn实现
在实际项目中我们通常使用scikit-learn库,它提供了高效且经过充分测试的实现:
from sklearn.linear_model import LinearRegression
import numpy as np
X = np.array([[1], [2], [3], [4], [5]])
y = np.array([2, 4, 5, 4, 6])
model = LinearRegression()
model.fit(X, y)
print(f"w={model.coef_[0]:.4f}, b={model.intercept_:.4f}")
print(f"R² score: {model.score(X, y):.4f}")
三、多元线性回归
3.1 多维特征的线性回归
实际应用中往往涉及多个特征。多元线性回归的形式为:y = w1x1 + w2x2 + ... + wnxn + b。用矩阵形式表示更加简洁:y = Xw + b,其中X是m×n的特征矩阵,w是n维权重向量。
3.2 正规方程(Normal Equation)
正规方程提供了一种直接求解最优参数的闭式解(closed-form solution),无需迭代:
正规方程的推导过程如下:将损失函数写成矩阵形式 J(w) = (1/2m)(Xw - y)T(Xw - y),对w求偏导并令其为零:
∂J/∂w = (1/m)XT(Xw - y) = 0
→ XTXw = XTy
→ w = (XTX)-1XTy
3.3 正规方程 vs 梯度下降对比
| 对比维度 | 正规方程 | 梯度下降 |
| 计算方式 | 直接求解闭式解 | 迭代优化 |
| 时间复杂度 | O(n3)(求逆矩阵) | O(kn)(k为迭代次数) |
| 特征数量 | 适合n < 10000 | 适合大规模特征 |
| 是否需要特征缩放 | 不需要 | 需要(加速收敛) |
| 可处理非线性 | 需手动添加多项式特征 | 同左 |
3.4 scikit-learn实现多元线性回归
from sklearn.linear_model import LinearRegression
from sklearn.datasets import make_regression
# 生成模拟数据:100个样本,5个特征
X, y = make_regression(n_samples=100, n_features=5,
noise=10, random_state=42)
model = LinearRegression()
model.fit(X, y)
print(f"权重: {model.coef_}")
print(f"截距: {model.intercept_:.4f}")
print(f"R² score: {model.score(X, y):.4f}")
四、模型评估
4.1 评估指标
评估回归模型性能的常用指标包括:
| 指标 | 公式 | 含义 |
| MSE | (1/m)Σ(yi - ŷi)2 | 均方误差,对异常值敏感 |
| RMSE | √MSE | 均方根误差,与原单位一致 |
| MAE | (1/m)Σ|yi - ŷi| | 平均绝对误差,鲁棒性更强 |
| R² | 1 - SSres/SStot | 决定系数,模型解释方差比例 |
4.2 R²得分(决定系数)
R²得分是最常用的回归评估指标之一,取值范围为(-∞, 1]。R² = 1表示完美拟合,R² = 0表示模型与简单取均值的效果相同,R² < 0表示模型比简单取均值还要差。调整R²(Adjusted R²)在R²的基础上引入了对特征数量的惩罚,防止过拟合:
Adjusted R² = 1 - (1 - R²)(n - 1)/(n - k - 1)
其中n为样本数,k为特征数。当增加无用的特征时,调整R²会下降。
4.3 Python计算评估指标
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import numpy as np
y_true = np.array([3.0, 5.0, 2.5, 7.0])
y_pred = np.array([2.8, 5.2, 2.3, 6.8])
mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_true, y_pred)
r2 = r2_score(y_true, y_pred)
print(f"MSE: {mse:.4f}")
print(f"RMSE: {rmse:.4f}")
print(f"MAE: {mae:.4f}")
print(f"R²: {r2:.4f}")
4.3 残差图分析
残差(residual)是预测值与真实值的差异。通过绘制残差图可以直观判断模型是否满足线性回归的基本假设。理想的残差图应呈现随机分布(围绕0对称),没有明显的模式或趋势。如果残差图呈现喇叭形或弯曲形,说明模型可能不满足同方差性或线性假设。
五、线性回归的假设
线性回归虽然简单高效,但它的有效性依赖于一系列统计假设。在使用线性回归时,我们需要检查这些假设是否满足:
5.1 线性关系(Linearity)
自变量x与因变量y之间必须存在线性关系。可以通过绘制散点图或残差图来验证。如果关系是非线性的,可以考虑使用多项式回归或特征变换。
5.2 误差独立性(Independence of Errors)
观测值之间应相互独立,即一个样本的误差不应与另一个样本的误差相关。对于时间序列数据尤其需要注意。Durbin-Watson检验可以用来检测自相关。
5.3 同方差性(Homoscedasticity)
残差的方差在所有的预测值水平上应保持恒定。如果方差随预测值变化(呈喇叭形),则存在异方差性(Heteroscedasticity),会导致参数估计不再有效。
5.4 误差正态分布(Normality of Errors)
残差应近似服从正态分布(均值为0)。这保证了参数估计和置信区间的有效性。可以使用Q-Q图或Shapiro-Wilk检验来验证。注意:大样本下中心极限定理使这一假设不那么关键。
5.5 多重共线性问题(Multicollinearity)
当特征之间存在高度相关性时,称为多重共线性。这会导致回归系数的估计不稳定且难以解释。可以通过方差膨胀因子(VIF, Variance Inflation Factor)来检测,通常VIF > 10表示存在严重的多重共线性。解决方法包括:删除相关特征、使用主成分分析(PCA)或采用正则化方法。
六、正则化线性回归
当特征数量较多或存在多重共线性时,普通最小二乘法可能会过拟合。正则化通过在损失函数中加入惩罚项来限制参数的大小,从而降低模型复杂度、提高泛化能力。
6.1 Ridge回归(L2正则化)
Ridge回归在损失函数中加入权重向量的L2范数平方作为惩罚项:
J(w) = MSE(w) + α * Σ(wj)2
Ridge回归倾向于让权重均匀地趋向于零(但不等于零),适合处理多重共线性问题。α是正则化强度参数,α越大正则化越强。
6.2 Lasso回归(L1正则化)
Lasso回归使用L1范数作为惩罚项:
J(w) = MSE(w) + α * Σ|wj|
Lasso的一个重要特性是能够将不重要的特征权重压缩到零,从而实现自动特征选择(feature selection)。这使得Lasso在高维数据中特别有用。
6.3 Elastic Net(弹性网络)
Elastic Net结合了Ridge和Lasso的惩罚项:
J(w) = MSE(w) + α * ρ * Σ|wj| + α * (1-ρ)/2 * Σ(wj)2
其中ρ是L1比率(l1_ratio),控制L1和L2惩罚的混合比例。Elastic Net在特征数量远大于样本数量时表现尤为出色。
6.4 scikit-learn实现
from sklearn.linear_model import Ridge, Lasso, ElasticNet
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
X, y = make_regression(n_samples=200, n_features=20,
noise=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42)
# 数据标准化(正则化方法要求特征处于相同尺度)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# Ridge回归
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
print(f"Ridge R²: {ridge.score(X_test, y_test):.4f}")
# Lasso回归
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
print(f"Lasso R²: {lasso.score(X_test, y_test):.4f}")
print(f"Lasso 非零特征数: {np.sum(lasso.coef_ != 0)}")
# Elastic Net
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)
elastic.fit(X_train, y_train)
print(f"ElasticNet R²: {elastic.score(X_test, y_test):.4f}")
6.5 正则化参数alpha的选择
α的选择对模型性能有重要影响。通常使用交叉验证(如RidgeCV、LassoCV)来自动选择最优的α值。scikit-learn提供了带交叉验证的正则化模型,极大地简化了调参过程。
from sklearn.linear_model import RidgeCV
alphas = [0.01, 0.1, 1.0, 10.0, 100.0]
ridge_cv = RidgeCV(alphas=alphas, cv=5)
ridge_cv.fit(X_train, y_train)
print(f"最佳alpha: {ridge_cv.alpha_}")
print(f"RidgeCV R²: {ridge_cv.score(X_test, y_test):.4f}")
七、多项式回归
7.1 多项式特征扩展
当数据呈现非线性关系时,可以通过多项式回归来拟合。多项式回归的核心思想是对原始特征进行多项式扩展,然后仍然使用线性回归模型进行拟合。例如,对于单特征x,二次多项式回归的模型为:y = w1x + w2x2 + b。
scikit-learn提供了PolynomialFeatures来生成多项式特征组合:
from sklearn.preprocessing import PolynomialFeatures
import numpy as np
X = np.array([[2], [3], [4]])
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
print("原始特征:\n", X)
print("多项式特征(degree=2):\n", X_poly)
# 输出: [[2, 4], [3, 9], [4, 16]]
7.2 过拟合与欠拟合的控制
多项式的阶数(degree)是控制模型复杂度的重要超参数。阶数过低会导致欠拟合(underfitting),无法捕捉数据中的非线性关系;阶数过高则可能导致过拟合(overfitting),对训练数据过度学习而失去泛化能力。通常通过交叉验证来选择合适的多项式阶数。
7.3 使用Pipeline构建完整流程
scikit-learn的Pipeline可以方便地将多个数据处理步骤串联起来,形成完整的工作流:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
# 构建管道:多项式特征扩展 → 线性回归
pipe = Pipeline([
('poly', PolynomialFeatures(degree=3, include_bias=False)),
('lr', LinearRegression())
])
# 使用管道进行交叉验证
scores = cross_val_score(pipe, X, y, cv=5,
scoring='r2')
print(f"交叉验证R²: {scores.mean():.4f} (+/- {scores.std():.4f})")
7.4 学习曲线分析
学习曲线(Learning Curve)是诊断模型偏差-方差问题的重要工具。通过绘制训练误差和验证误差随训练样本数量的变化曲线,可以判断模型处于欠拟合(高偏差)还是过拟合(高方差)状态:
- 高偏差(欠拟合):训练误差和验证误差都很高,且趋于收敛。增加数据量无法改善性能,需要增加模型复杂度。
- 高方差(过拟合):训练误差很低但验证误差很高,两条曲线之间存在较大差距。增加数据量或降低模型复杂度有助于缓解。
八、核心要点总结
1. 线性回归是监督学习的基石——理解线性回归有助于掌握更复杂的模型。
2. 求解方法——小数据量优先使用正规方程(闭式解),大数据量使用梯度下降。
3. 特征工程至关重要——多项式特征扩展可以将线性模型应用于非线性问题。
4. 正则化是防止过拟合的关键——Ridge适合处理多重共线性,Lasso适合特征选择,Elastic Net是两者的平衡。
5. 模型诊断——检查残差图、R²得分和学习曲线,确保模型假设得到满足。
6. 数据预处理——正则化方法要求特征标准化,多项式回归需要谨慎选择阶数。