摘要
线性回归与岭回归是机器学习中最基础、最重要的监督学习算法之一,广泛应用于房价预测、销量分析、金融风控等实际场景。本文从原理出发,详细推导线性回归的假设函数、损失函数、正规方程与梯度下降求解方法,并扩展到多元线性回归与特征缩放;随后介绍岭回归的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 何时选择岭回归
适合使用岭回归的场景:
-
特征维度接近或超过样本量:此时普通线性回归过拟合风险极高
-
存在多重共线性:特征之间存在高度相关性(如身高cm和体重kg)
-
所有特征都有一定预测价值:不希望像Lasso那样将某些系数直接置为0
-
参数正则化:希望约束模型参数的范数,防止异常值影响过大
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 实战建议
-
优先使用 scikit-learn:API统一、文档完善,适合快速原型开发
-
始终进行特征缩放:梯度下降类算法必须缩放;正规方程可不做
-
使用交叉验证选择正则化参数:避免在测试集上直接调参导致过拟合
-
检查残差分布:理想情况下残差应呈均值为0的正态分布
-
注意异常值:线性回归对异常值敏感,可考虑使用RANSAC或Huber回归
-
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}")