机器学习之线性回归与岭回归详解

摘要

线性回归与岭回归是机器学习中最基础、最重要的监督学习算法之一,广泛应用于房价预测、销量分析、金融风控等实际场景。本文从原理出发,详细推导线性回归的假设函数、损失函数、正规方程与梯度下降求解方法,并扩展到多元线性回归与特征缩放;随后介绍岭回归的L2正则化机制及其防止过拟合的原理;最后通过scikit-learn提供多个完整可运行的Python实战示例,涵盖单变量线性回归、多元线性回归、岭回归与普通线性回归对比,以及真实数据集上的综合应用。通过本文,读者可全面掌握线性回归与岭回归的理论与实践,能够在实际项目中正确选型并快速落地。

关键词:线性回归;岭回归;正则化;梯度下降;scikit-learn;机器学习


1. 线性回归基础

1.1 什么是线性回归

线性回归(Linear Regression)是机器学习中最经典的算法之一,它试图找到一条直线(或一个平面、超平面),使得预测值与真实值之间的误差最小。简单来说,线性回归研究的是变量之间的线性关系。

例如,房子的面积与价格之间通常存在近似线性的关系------面积越大,价格越高。线性回归正是用来刻画这种关系的数学工具。

1.2 假设函数

线性回归的假设函数(Hypothesis Function)定义为:

h_\\theta(x) = \\theta_0 + \\theta_1 x

为了便于矩阵表示,我们通常在特征向量前添加一个全1的列,将截距项 b 也纳入参数向量:

h(\\mathbf{x}) = \\mathbf{w}\^T \\mathbf{x} + b

其中:

  • \\mathbf{w} 为权重向量(包含偏置 b,通过增广实现)

  • \\mathbf{x} 为特征向量

代码示例:定义线性回归假设函数

复制代码
import numpy as np
​
def hypothesis(X, w, b):
    """
    线性回归假设函数
    参数:
        X: 特征矩阵 (n_samples, n_features)
        w: 权重向量 (n_features,)
        b: 偏置标量
    返回:
        y_pred: 预测值向量 (n_samples,)
    """
    return np.dot(X, w) + b
​
# 示例:单个特征的假设函数
x = np.array([50, 60, 70, 80, 90])  # 房屋面积(平方米)
w = 0.5  # 权重
b = 10   # 偏置
​
y_pred = hypothesis(x, w, b)
print("特征值:", x)
print("预测值:", y_pred)

1.3 损失函数:均方误差(MSE)

线性回归使用均方误差(Mean Squared Error,MSE)作为损失函数:

J(\\mathbf{w}) = \\frac{1}{2m} \\sum*{i=1}\^{m} \\left( h*\\theta(\\mathbf{x}\^{(i)}) - y\^{(i)} \\right)\^2

其中:

  • m 为样本数量

  • h_\\theta(\\mathbf{x}\^{(i)}) 为第 i 个样本的预测值

  • y\^{(i)} 为第 i 个样本的真实值

MSE衡量的是预测值与真实值之间差距的平方的均值。系数 \\frac{1}{2} 是为了方便后续梯度计算(与平方抵消)。

代码示例:计算均方误差损失

复制代码
def mean_squared_error(y_true, y_pred):
    """
    计算均方误差(MSE)
    参数:
        y_true: 真实值向量 (n_samples,)
        y_pred: 预测值向量 (n_samples,)
    返回:
        mse: 均方误差值
    """
    m = len(y_true)
    mse = np.sum((y_pred - y_true) ** 2) / (2 * m)
    return mse
​
# 示例
y_true = np.array([35, 40, 45, 50, 55])  # 真实房价(万元)
y_pred = np.array([33, 42, 44, 52, 53])  # 预测房价
​
mse = mean_squared_error(y_true, y_pred)
print(f"均方误差 (MSE): {mse:.4f}")

1.4 正规方程求解

对于线性回归,可以通过正规方程(Normal Equation)直接解析地求出最优参数:

\\mathbf{w} = (\\mathbf{X}\^T \\mathbf{X})\^{-1} \\mathbf{X}\^T \\mathbf{y}

其中:

  • \\mathbf{X}m \\times n 的特征矩阵(包含偏置列)

  • \\mathbf{y}m \\times 1 的目标向量

优点 :无需迭代,直接计算得到全局最优解 缺点:当特征维度 n 很大时,矩阵求逆复杂度为 O(n\^3),计算量大
代码示例:使用正规方程求解线性回归

复制代码
def normal_equation(X, y):
    """
    使用正规方程求解线性回归参数
    参数:
        X: 特征矩阵 (m, n),不含偏置列
        y: 目标向量 (m,)
    返回:
        w: 权重向量 (n,)
        b: 偏置标量
    """
    # 拼接偏置列:将偏置b作为w的一部分,通过在X前加一列全1实现
    X_b = np.c_[np.ones((X.shape[0], 1)), X]  # (m, n+1)
​
    # 正规方程: theta = (X^T * X)^(-1) * X^T * y
    # 使用 np.linalg.pinv 进行伪逆计算,数值更稳定
    theta = np.linalg.pinv(X_b.T @ X_b) @ X_b.T @ y
​
    b = theta[0]
    w = theta[1:]
    return w, b
​
# 示例:简单的一元线性回归
X = np.array([[50], [60], [70], [80], [90], [100]])  # 房屋面积
y = np.array([35, 42, 48, 55, 60, 68])  # 房屋价格(万元)
​
w, b = normal_equation(X, y)
print(f"权重 w: {w[0]:.4f}")
print(f"偏置 b: {b:.4f}")
​
# 使用求得的参数进行预测
y_pred = hypothesis(X, w, b)
print("预测值:", y_pred)
print("真实值:", y)
print(f"MSE: {mean_squared_error(y, y_pred):.4f}")

1.5 梯度下降求解

梯度下降(Gradient Descent)是另一种求解线性回归参数的方法,尤其适用于大规模数据集或特征维度较高的情况。

参数更新规则:

\\mathbf{w} := \\mathbf{w} - \\alpha \\cdot \\frac{\\partial J(\\mathbf{w})}{\\partial \\mathbf{w}}

对于MSE损失函数,梯度为:

\\frac{\\partial J}{\\partial \\mathbf{w}} = \\frac{1}{m} \\mathbf{X}\^T (\\mathbf{X} \\mathbf{w} - \\mathbf{y})

其中 \\alpha 为学习率(Learning Rate)。

代码示例:使用梯度下降训练线性回归

复制代码
def gradient_descent(X, y, lr=0.01, n_iterations=1000):
    """
    使用梯度下降训练线性回归
    参数:
        X: 特征矩阵 (m, n)
        y: 目标向量 (m,)
        lr: 学习率
        n_iterations: 迭代次数
    返回:
        w: 权重向量 (n,)
        b: 偏置标量
        cost_history: 损失值历史记录
    """
    m, n = X.shape
​
    # 初始化参数
    w = np.zeros(n)
    b = 0
    cost_history = []
​
    for i in range(n_iterations):
        # 前向传播:计算预测值
        y_pred = np.dot(X, w) + b
​
        # 计算损失
        cost = mean_squared_error(y, y_pred)
        cost_history.append(cost)
​
        # 计算梯度
        dw = (1 / m) * np.dot(X.T, (y_pred - y))  # (n,)
        db = (1 / m) * np.sum(y_pred - y)          # scalar
​
        # 更新参数
        w = w - lr * dw
        b = b - lr * db
​
        # 每100次迭代打印一次进度
        if (i + 1) % 100 == 0:
            print(f"迭代 {i+1:4d}: MSE = {cost:.6f}")
​
    return w, b, cost_history
​
# 示例
X = np.array([[50], [60], [70], [80], [90], [100]])
y = np.array([35, 42, 48, 55, 60, 68])
​
w, b, cost_history = gradient_descent(X, y, lr=0.0001, n_iterations=1000)
print(f"\n最终权重 w: {w[0]:.6f}")
print(f"最终偏置 b: {b:.6f}")
​
# 绘制损失曲线
import matplotlib.pyplot as plt
plt.plot(cost_history)
plt.xlabel('迭代次数')
plt.ylabel('MSE 损失')
plt.title('梯度下降损失曲线')
plt.grid(True)
plt.show()

2. 多元线性回归

2.1 多特征情况

现实中的问题往往涉及多个特征。例如,房价不仅与面积有关,还与房间数、房龄、地段等因素相关。多元线性回归的假设函数为:

h(\\mathbf{x}) = \\mathbf{w}\^T \\mathbf{x} + b = w_1 x_1 + w_2 x_2 + \\cdots + w_n x_n + b

代码示例:多元线性回归实战

复制代码
def multivariate_linear_regression(X, y, lr=0.01, n_iterations=1000):
    """
    多元线性回归(使用梯度下降)
    参数:
        X: 特征矩阵 (m, n),m个样本,n个特征
        y: 目标向量 (m,)
        lr: 学习率
        n_iterations: 迭代次数
    返回:
        w: 权重向量 (n,)
        b: 偏置标量
    """
    m, n = X.shape
    w = np.zeros(n)
    b = 0
​
    for i in range(n_iterations):
        y_pred = np.dot(X, w) + b
        dw = (1 / m) * np.dot(X.T, (y_pred - y))
        db = (1 / m) * np.sum(y_pred - y)
        w = w - lr * dw
        b = b - lr * db
​
    return w, b
​
# 示例:房价预测(面积、房间数、房龄)
X = np.array([
    [50, 2, 10],   # 面积50平,2室,10年房龄
    [80, 3, 5],    # 面积80平,3室,5年房龄
    [100, 3, 2],   # 面积100平,3室,2年房龄
    [65, 2, 8],    # 面积65平,2室,8年房龄
    [90, 3, 3],    # 面积90平,3室,3年房龄
])
y = np.array([100, 180, 250, 130, 210])  # 房价(万元)
​
w, b = multivariate_linear_regression(X, y, lr=0.0001, n_iterations=5000)
print(f"权重 w: {w}")
print(f"偏置 b: {b:.4f}")
​
# 预测新房子
new_house = np.array([[75, 3, 6]])  # 75平,3室,6年房龄
price_pred = np.dot(new_house, w) + b
print(f"\n新房子预测价格: {price_pred[0]:.2f} 万元")

2.2 特征缩放的重要性

在多元线性回归中,不同特征的量纲和数值范围可能差异巨大。例如,面积范围是50~200(平方米),房间数范围是1~5(间)。如果不进行特征缩放,梯度下降的等高线将呈狭长的椭圆形,导致收敛极慢。

常用的特征缩放方法有两种:

1. 标准化(Standardization): $$x' = \frac{x - \mu}{\sigma}$$ 其中 \\mu 为均值,\\sigma 为标准差。

2. 归一化(Min-Max Normalization) : $$x' = \frac{x - x*{\min}}{x*{\max} - x_{\min}}$$

代码示例:特征缩放实现与效果对比

复制代码
def standardize(X):
    """标准化特征"""
    mean = np.mean(X, axis=0)
    std = np.std(X, axis=0)
    # 避免除以0
    std[std == 0] = 1
    return (X - mean) / std, mean, std
​
def min_max_normalize(X):
    """Min-Max归一化"""
    min_val = np.min(X, axis=0)
    max_val = np.max(X, axis=0)
    range_val = max_val - min_val
    range_val[range_val == 0] = 1  # 避免除以0
    return (X - min_val) / range_val, min_val, max_val
​
# 示例:对比缩放前后的梯度下降
X_raw = np.array([
    [2000, 3, 20],   # 面积2000平方英尺
    [1500, 2, 10],
    [3000, 4, 5],
    [2500, 3, 15],
    [1800, 2, 8],
])
y_raw = np.array([250, 200, 400, 320, 260])  # 房价(万美元)
​
print("=== 未缩放的特征 ===")
w_raw, b_raw, _ = gradient_descent(X_raw, y_raw, lr=0.000001, n_iterations=100)
print(f"权重: {w_raw}")
​
print("\n=== 标准化后的特征 ===")
X_std, mean, std = standardize(X_raw)
w_std, b_std, cost_std = gradient_descent(X_std, y_raw, lr=0.1, n_iterations=100)
print(f"权重: {w_std}")

3. 使用 scikit-learn 实现线性回归

3.1 单变量线性回归:房价预测

scikit-learn 提供了简洁的API来训练线性回归模型。

代码示例:使用 scikit-learn 实现房价预测

复制代码
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np
​
# 构造模拟房价数据:面积 -> 价格
# 假设关系为: price = 0.5 * area + 10 + noise
np.random.seed(42)
area = np.linspace(50, 200, 100)  # 面积: 50~200平方米
noise = np.random.randn(100) * 5  # 随机噪声
price = 0.5 * area + 10 + noise   # 价格(万元)
​
# 转换为2D数组(scikit-learn要求)
X = area.reshape(-1, 1)
y = price
​
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
​
# 创建并训练模型
model = LinearRegression()
model.fit(X_train, y_train)
​
# 打印模型参数
print(f"斜率(权重): {model.coef_[0]:.4f}")
print(f"截距: {model.intercept_:.4f}")
​
# 在测试集上预测
y_pred = model.predict(X_test)
​
# 评估模型
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
rmse = np.sqrt(mse)
​
print(f"\n=== 模型评估 ===")
print(f"均方误差 (MSE): {mse:.4f}")
print(f"均方根误差 (RMSE): {rmse:.4f}")
print(f"R² 分数: {r2:.4f}")
​
# 可视化结果
import matplotlib.pyplot as plt
plt.scatter(X_test, y_test, color='blue', label='真实值')
plt.plot(X_test, y_pred, color='red', linewidth=2, label='预测值')
plt.xlabel('面积(平方米)')
plt.ylabel('价格(万元)')
plt.title('房价预测:线性回归')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

3.2 多元线性回归:糖尿病病情预测

使用 scikit-learn 内置的糖尿病数据集(Diabetes Dataset)进行多元线性回归。

代码示例:多元线性回归实战------糖尿病病情预测

复制代码
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
import numpy as np
​
# 加载糖尿病数据集
# 该数据集包含10个特征(年龄、性别、BMI、血压等)和一个连续的目标值(一年后疾病进展的量化指标)
diabetes = load_diabetes()
X = diabetes.data   # (442, 10)
y = diabetes.target  # (442,)
​
print("数据集形状:", X.shape)
print("特征名称:", diabetes.feature_names)
print("目标值范围:", y.min(), "~", y.max())
​
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
​
# 训练多元线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)
​
# 预测
y_pred = model.predict(X_test)
​
# 评估指标
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
​
print(f"\n=== 多元线性回归评估结果 ===")
print(f"均方误差 (MSE): {mse:.4f}")
print(f"均方根误差 (RMSE): {rmse:.4f}")
print(f"平均绝对误差 (MAE): {mae:.4f}")
print(f"R² 分数: {r2:.4f}")
​
# 查看各特征的系数(反映各特征对预测结果的贡献)
print(f"\n各特征的系数:")
for name, coef in zip(diabetes.feature_names, model.coef_):
    print(f"  {name}: {coef:+.4f}")

4. 岭回归(L2正则化)

4.1 什么是岭回归

岭回归(Ridge Regression)是线性回归的改进版本,通过在损失函数中添加L2正则化项来防止过拟合。

普通线性回归的损失函数: $$J(\mathbf{w}) = \frac{1}{2m} \sum_{i=1}^{m} \left( h(\mathbf{x}^{(i)}) - y^{(i)} \right)^2$$

岭回归的损失函数: $$J(\mathbf{w}) = \frac{1}{2m} \sum*{i=1}^{m} \left( h(\mathbf{x}^{(i)}) - y^{(i)} \right)^2 + \lambda \sum*{j=1}^{n} w_j^2$$

其中 \\lambda \\geq 0 为正则化参数,\\lambda \\sum_{j=1}\^{n} w_j\^2 为L2正则化项。

4.2 正则化原理

L2正则化的核心思想是对大的权重施加惩罚,从而约束模型的复杂度:

  • \\lambda = 0 时,岭回归退化为普通线性回归

  • \\lambda 增大时,所有权重向0收缩,模型变得更简单

  • L2正则化不会将权重设为 exactly 0,而是使其接近0,从而保留所有特征的影响

4.3 正规方程求解

岭回归的解析解为:

\\mathbf{w} = (\\mathbf{X}\^T \\mathbf{X} + \\lambda \\mathbf{I})\^{-1} \\mathbf{X}\^T \\mathbf{y}

其中 \\mathbf{I}n \\times n 的单位矩阵。注意,这里没有对偏置项施加正则化。

代码示例:岭回归正规方程实现

复制代码
def ridge_regression_normal(X, y, lambda_param):
    """
    使用正规方程求解岭回归
    参数:
        X: 特征矩阵 (m, n),不含偏置列
        y: 目标向量 (m,)
        lambda_param: 正则化参数 lambda
    返回:
        w: 权重向量 (n,)
        b: 偏置标量
    """
    m, n = X.shape
    X_b = np.c_[np.ones((m, 1)), X]  # 拼接偏置列 -> (m, n+1)
​
    # 岭回归正规方程:(X^T*X + lambda*I)^(-1) * X^T*y
    # 单位矩阵的左上角元素为0(不对偏置正则化)
    I = np.eye(n + 1)
    I[0, 0] = 0  # 偏置项不参与正则化
​
    # 使用 np.linalg.solve 求解线性系统,比直接求逆更稳定
    theta = np.linalg.solve(
        X_b.T @ X_b + lambda_param * I,
        X_b.T @ y
    )
​
    b = theta[0]
    w = theta[1:]
    return w, b
​
# 示例:对比不同lambda值的岭回归
np.random.seed(42)
X = np.random.randn(100, 5)  # 5个特征
y = 3*X[:, 0] + 2*X[:, 1] - X[:, 2] + np.random.randn(100) * 0.5
​
for lam in [0, 0.1, 1, 10, 100]:
    w, b = ridge_regression_normal(X, y, lam)
    print(f"λ={lam:6.1f}: w = {w.round(3)}")

4.4 scikit-learn 实现岭回归

代码示例:使用 scikit-learn 实现岭回归

复制代码
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np
​
# 生成模拟数据(带噪声的高维数据)
# 使用 make_regression 生成一个有多重共线性问题的数据集
X, y = make_regression(
    n_samples=200,    # 样本数
    n_features=50,   # 特征数(高维)
    n_informative=10, # 真正有信息量的特征数
    noise=20,         # 噪声标准差
    random_state=42,
    bias=10
)
​
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
​
# 训练普通线性回归(对照)
lr_model = LinearRegression()
lr_model.fit(X_train, y_train)
y_pred_lr = lr_model.predict(X_test)
​
# 训练岭回归(不同alpha值)
print("=== 岭回归 vs 普通线性回归 ===\n")
print(f"{'模型':<25} {'MSE':>12} {'R²':>10}")
print("-" * 50)
​
for alpha in [0.01, 0.1, 1.0, 10.0, 100.0]:
    ridge = Ridge(alpha=alpha)
    ridge.fit(X_train, y_train)
    y_pred = ridge.predict(X_test)
    mse = mean_squared_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    print(f"岭回归 (α={alpha:<6.1f})     {mse:>12.4f} {r2:>10.4f}")
​
print(f"{'普通线性回归':<25} {mean_squared_error(y_test, y_pred_lr):>12.4f} {r2_score(y_test, y_pred_lr):>10.4f}")
​
# 查看权重分布:岭回归的权重更小、更集中
print(f"\n普通线性回归权重范数: {np.linalg.norm(lr_model.coef_):.4f}")
print(f"岭回归(α=1.0)权重范数: {np.linalg.norm(ridge.coef_):.4f}")

5. 线性回归与岭回归对比实战

5.1 过拟合场景下的对比

当模型过于复杂(特征过多、参数过多)时,普通线性回归容易过拟合。岭回归通过正则化可以有效缓解这一问题。

代码示例:过拟合与正则化效果对比

复制代码
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
import numpy as np
import matplotlib.pyplot as plt
​
# 生成存在多重共线性的数据
X, y = make_regression(
    n_samples=100,
    n_features=100,   # 特征数 >> 样本数(容易过拟合)
    n_informative=5,
    noise=10,
    random_state=42,
    coef=False
)
y = y.reshape(-1)
​
# 普通线性回归 vs 岭回归 vs Lasso
models = {
    '普通线性回归': LinearRegression(),
    '岭回归 (α=1.0)': Ridge(alpha=1.0),
    '岭回归 (α=10.0)': Ridge(alpha=10.0),
    '岭回归 (α=100.0)': Ridge(alpha=100.0),
}
​
print("=== 过拟合场景下的模型对比 ===\n")
print(f"{'模型':<25} {'训练R²':>10} {'测试R²':>10} {'5折交叉验证R²':>15}")
print("-" * 65)
​
for name, model in models.items():
    model.fit(X, y)
    train_score = model.score(X, y)
​
    # 在原始数据上再切分测试集
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42
    )
    model2 = model.__class__(**model.get_params())
    model2.fit(X_train, y_train)
    test_score = model2.score(X_test, y_test)
​
    # 交叉验证
    cv_scores = cross_val_score(model, X, y, cv=5, scoring='r2')
    cv_mean = cv_scores.mean()
​
    print(f"{name:<25} {train_score:>10.4f} {test_score:>10.4f} {cv_mean:>15.4f}")
​
# 可视化不同alpha下权重系数的变化
alphas = np.logspace(-4, 4, 50)
coefs = []
for alpha in alphas:
    ridge = Ridge(alpha=alpha)
    ridge.fit(X, y)
    coefs.append(ridge.coef_)
​
coefs = np.array(coefs)
plt.figure(figsize=(10, 6))
plt.semilogx(alphas, coefs, alpha=0.5)
plt.xlabel('正则化参数 α')
plt.ylabel('权重系数')
plt.title('岭回归:正则化参数α对权重的影响')
plt.grid(True, alpha=0.3)
plt.axvline(x=1.0, color='r', linestyle='--', label='α=1.0')
plt.legend()
plt.show()

5.2 使用 sklearn 内置糖尿病数据集的综合对比

代码示例:糖尿病预测------线性回归 vs 岭回归 vs Lasso

复制代码
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.datasets import load_diabetes
from sklearn.model_selection import cross_val_score, KFold
from sklearn.metrics import mean_squared_error
import numpy as np
​
# 加载糖尿病数据集
diabetes = load_diabetes()
X = diabetes.data
y = diabetes.target
​
print("=== 糖尿病病情预测:多模型对比 ===\n")
​
# 定义模型
models = {
    '普通线性回归': LinearRegression(),
    '岭回归 (α=0.1)': Ridge(alpha=0.1),
    '岭回归 (α=1.0)': Ridge(alpha=1.0),
    '岭回归 (α=10.0)': Ridge(alpha=10.0),
    'Lasso (α=0.1)': Lasso(alpha=0.1),
    'Lasso (α=1.0)': Lasso(alpha=1.0),
}
​
cv = KFold(n_splits=5, shuffle=True, random_state=42)
​
print(f"{'模型':<25} {'5折CV均方误差':>18} {'平均R²':>10}")
print("-" * 58)
​
for name, model in models.items():
    # 交叉验证(负MSE,取反后更直观)
    neg_mse_scores = cross_val_score(model, X, y, cv=cv, scoring='neg_mean_squared_error')
    mse_scores = -neg_mse_scores
    cv_mse = mse_scores.mean()
​
    r2_scores = cross_val_score(model, X, y, cv=cv, scoring='r2')
    cv_r2 = r2_scores.mean()
​
    print(f"{name:<25} {cv_mse:>18.4f} {cv_r2:>10.4f}")

6. 线性回归与岭回归的使用场景

6.1 房价预测

房价预测是线性回归最经典的应用场景之一。特征通常包括:

  • 房屋面积(平方米)

  • 房间数量、卫生间数量

  • 房龄

  • 地段(经纬度、距市中心距离)

  • 周边配套设施

线性回归可以快速建立面积、房间数等与价格之间的关系,为房产估值提供参考。

6.2 销量预测

在零售和供应链管理中,线性回归用于预测产品销量。相关特征包括:

  • 价格

  • 广告投放金额

  • 促销活动

  • 季节性因素

  • 竞争对手价格

通过多元线性回归,企业可以量化各因素对销量的影响,优化营销策略。

6.3 趋势分析

线性回归可用于分析时间序列数据的趋势,例如:

  • 网站月访问量增长趋势

  • 社交媒体粉丝增长趋势

  • 股票价格长期走势

通过拟合一条趋势线,可以量化增长(衰减)速率,为决策提供数据支撑。

6.4 金融领域的回归分析

金融领域广泛使用回归分析进行:

  • 风险定价:根据公司财务指标预测信用风险

  • 资产定价:CAPM模型中,资产收益率与市场收益率的线性关系

  • 套利定价:多因子模型中,收益率与多个风险因子的线性关系

  • 收益预测:根据宏观经济指标预测资产收益

6.5 何时选择岭回归

适合使用岭回归的场景:

  1. 特征维度接近或超过样本量:此时普通线性回归过拟合风险极高

  2. 存在多重共线性:特征之间存在高度相关性(如身高cm和体重kg)

  3. 所有特征都有一定预测价值:不希望像Lasso那样将某些系数直接置为0

  4. 参数正则化:希望约束模型参数的范数,防止异常值影响过大


7. 线性回归的模型评估指标

除了MSE之外,线性回归还有其他常用评估指标:

代码示例:完整的模型评估体系

复制代码
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import numpy as np
​
# 加载数据
diabetes = load_diabetes()
X_train, X_test, y_train, y_test = train_test_split(
    diabetes.data, diabetes.target, test_size=0.2, random_state=42
)
​
# 训练模型
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
​
# 各项评估指标
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
​
# 计算SST、SSE、SSR
y_mean = np.mean(y_test)
sst = np.sum((y_test - y_mean) ** 2)  # 总平方和
sse = np.sum((y_test - y_pred) ** 2)  # 残差平方和
ssr = np.sum((y_pred - y_mean) ** 2)  # 回归平方和
​
print("=== 线性回归模型评估指标 ===\n")
print(f"1. 均方误差 (MSE): {mse:.4f}")
print(f"2. 均方根误差 (RMSE): {rmse:.4f}")
print(f"3. 平均绝对误差 (MAE): {mae:.4f}")
print(f"4. R² (决定系数): {r2:.4f}")
print(f"\n5. 分解验证:")
print(f"   SST (总平方和) = {sst:.4f}")
print(f"   SSE (残差平方和) = {sse:.4f}")
print(f"   SSR (回归平方和) = {ssr:.4f}")
print(f"   SSE + SSR = {sse + ssr:.4f} (应 ≈ SST)")
print(f"   R² = SSR / SST = {ssr/sst:.4f}")

8. 总结与实战建议

8.1 核心知识点回顾

知识点 线性回归 岭回归
损失函数 MSE MSE + L2正则化
参数求解 正规方程 / 梯度下降 正规方程 / 梯度下降
过拟合控制 L2正则化
特征选择 不稀疏 不稀疏(权重收缩)
参数 \\lambda 需要调参

8.2 实战建议

  1. 优先使用 scikit-learn:API统一、文档完善,适合快速原型开发

  2. 始终进行特征缩放:梯度下降类算法必须缩放;正规方程可不做

  3. 使用交叉验证选择正则化参数:避免在测试集上直接调参导致过拟合

  4. 检查残差分布:理想情况下残差应呈均值为0的正态分布

  5. 注意异常值:线性回归对异常值敏感,可考虑使用RANSAC或Huber回归

  6. R²不是唯一标准:高R²不代表模型真的好,需结合业务场景综合判断

8.3 代码模板

以下是生产环境中使用线性回归和岭回归的推荐模板:

复制代码
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error, r2_score
​
# 推荐:使用Pipeline将预处理和建模串联
pipeline = Pipeline([
    ('scaler', StandardScaler()),       # 特征标准化
    ('regressor', Ridge())              # 岭回归(可替换为LinearRegression)
])
​
# 参数网格搜索
param_grid = {
    'regressor__alpha': [0.01, 0.1, 1.0, 10.0, 100.0]
}
​
grid_search = GridSearchCV(
    pipeline, param_grid, cv=5, scoring='r2', n_jobs=-1
)
grid_search.fit(X_train, y_train)
​
# 输出最优参数和得分
print(f"最优alpha: {grid_search.best_params_['regressor__alpha']}")
print(f"最优交叉验证R²: {grid_search.best_score_:.4f}")
​
# 在测试集上评估
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
print(f"测试集R²: {r2_score(y_test, y_pred):.4f}")
print(f"测试集MSE: {mean_squared_error(y_test, y_pred):.4f}")

相关推荐
DogDaoDao1 小时前
【GitHub】SuperClaude Framework深度解析:将Claude Code打造为专业开发平台的元编程配置框架
人工智能·深度学习·程序员·大模型·github·ai编程·claude
技术程序猿华锋1 小时前
Hermes Agent 深度实战:安装部署、Docker 配置、API 接入与生产环境最佳实践教程
运维·人工智能·docker·容器·agi
数据门徒1 小时前
神经网络原理 第六章:支持向量机
神经网络·机器学习·支持向量机
暗夜猎手-大魔王1 小时前
OpenClaw上下文工程学习
人工智能
情绪总是阴雨天~1 小时前
机器学习与深度学习核心问题解决方案:过拟合与样本不均衡
人工智能·深度学习·机器学习
AI科技星2 小时前
基于代数拓扑与等腰梯形素数对网格【乖乖数学】
人工智能·算法·决策树·机器学习·数学建模·数据挖掘·机器人
2zcode2 小时前
基于MATLAB与SVM实现河道水面漂浮物的自动检测与识别
人工智能·支持向量机·matlab
王钧石的技术博客2 小时前
Harness Engineering学习
人工智能·学习·agent
YangYang9YangYan2 小时前
2026财务分析师岗位学数据分析的价值分析
人工智能·数据挖掘·数据分析