本文参考了周志华老师的《机器学习》(俗称“西瓜书”)。这里是 第三章“线性模型” 的阅读笔记。本文专注于线性回归这一块,并且记录了我的思考,希望对你有所帮助🎉
一、线性模型基本概念
线性模型是机器学习的基础模型之一,假设目标值 (y) 与输入特征 (x) 之间的关系是一个线性组合。
二、线性回归公式推导
为了推导出最优的 (w) 和 (b),我们需要最小化损失函数 (L(w, b))。以下是完整推导过程:
三、从零实现线性回归
使用 Python 完全从零实现线性回归,包括数据生成、解析解计算和模型预测。
import numpy as np
# 1. 生成模拟数据
np.random.seed(42)
m = 100 # 样本数量
n = 1 # 特征数量
X = 2 * np.random.rand(m, n) # 输入特征矩阵
true_w = np.array([[3]]) # 真实权重
true_b = 5 # 真实偏置
y = X.dot(true_w) + true_b # 真实目标值
y += np.random.randn(m, 1) # 添加高斯噪声
# 2. 实现线性回归解析解
def linear_regression(X, y):
"""实现线性回归解析解"""
m = len(X)
X_b = np.c_[X, np.ones((m, 1))] # 添加偏置项 (X_b = [X, 1])
theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) # 解析解公式
return theta
# 3. 计算权重和偏置
theta = linear_regression(X, y)
w_hat = theta[:-1] # 权重
b_hat = theta[-1] # 偏置
print(f"真实权重: {true_w.flatten()}, 预测权重: {w_hat.flatten()}")
print(f"真实偏置: {true_b}, 预测偏置: {b_hat}")
# 4. 预测函数
def predict(X, w, b):
return X.dot(w) + b
# 5. 可视化结果
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
plt.scatter(X, y, color="blue", label="真实数据")
y_pred = predict(X, w_hat, b_hat)
plt.plot(X, y_pred, color="red", label="拟合直线")
plt.xlabel("特征 X")
plt.ylabel("目标 y")
plt.legend()
plt.title("线性回归:从零实现")
plt.show()
四、结果分析
- 输出:
真实权重: [3], 预测权重: [2.77011339]
真实偏置: 5, 预测偏置: [5.21509616]
五、头脑风暴
1.手写版公式推导过程
2.可以加入梯度下降来优化线性回归
简单解释
梯度下降是一种迭代优化算法,用于通过不断调整参数)来最小化损失函数。相比解析解(直接计算),梯度下降更加适合大规模数据集,因为它避免了矩阵求逆的高计算成本。
优点:
- 适用于大规模数据。
- 可以逐步逼近全局最优解。
3.正则化(L1/L2)处理过拟合
简单解释
正则化通过在损失函数中增加一个惩罚项,限制模型参数的大小,从而防止过拟合。主要有两种形式:
正则化的意义:
- 防止模型过度拟合训练数据。
- 提高模型对新数据的泛化能力。
4.更简单的代码显示
4.1. 使用 PyTorch 实现线性回归
代码实现
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
# 1. 生成数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1).astype(np.float32)
y = 3 * X + 5 + np.random.randn(100, 1).astype(np.float32) # y = 3X + 5 + 噪声
# 转换为 PyTorch 张量
X_tensor = torch.from_numpy(X)
y_tensor = torch.from_numpy(y)
# 2. 定义模型
class LinearRegressionModel(nn.Module):
def __init__(self):
super(LinearRegressionModel, self).__init__()
self.linear = nn.Linear(1, 1) # 输入维度 1,输出维度 1
def forward(self, x):
return self.linear(x)
# 创建模型实例
model = LinearRegressionModel()
# 3. 定义损失函数和优化器
criterion = nn.MSELoss() # 均方误差损失
optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # 随机梯度下降
# 4. 训练模型
epochs = 1000
losses = []
for epoch in range(epochs):
# 前向传播
y_pred = model(X_tensor)
loss = criterion(y_pred, y_tensor)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 记录损失
losses.append(loss.item())
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss.item():.4f}")
# 5. 获取权重和偏置
w, b = model.linear.weight.item(), model.linear.bias.item()
print(f"预测权重: {w:.2f}, 预测偏置: {b:.2f}")
# 6. 结果
y_pred = model(X_tensor).detach().numpy() # 获取预测值
4.2. 使用 Scikit-learn 实现线性回归(带正则化)
a. 普通线性回归
from sklearn.linear_model import LinearRegression
# 1. 创建模型并训练
model = LinearRegression()
model.fit(X, y)
# 2. 获取权重和偏置
w_hat = model.coef_[0][0]
b_hat = model.intercept_[0]
print(f"预测权重: {w_hat:.2f}, 预测偏置: {b_hat:.2f}")
# 3. 结果
y_pred = model.predict(X)
b. 带正则化的线性回归(Ridge 和 Lasso)
Ridge 回归(L2 正则化)
from sklearn.linear_model import Ridge
# 1. 创建 Ridge 模型
ridge_model = Ridge(alpha=1.0) # alpha 控制正则化强度
ridge_model.fit(X, y)
# 2. 获取权重和偏置
w_hat = ridge_model.coef_[0][0]
b_hat = ridge_model.intercept_[0]
print(f"Ridge 回归预测权重: {w_hat:.2f}, 预测偏置: {b_hat:.2f}")
# 3. 可结果
y_pred_ridge = ridge_model.predict(X)
Lasso 回归(L1 正则化)
from sklearn.linear_model import Lasso
# 1. 创建 Lasso 模型
lasso_model = Lasso(alpha=0.1) # alpha 控制正则化强度
lasso_model.fit(X, y)
# 2. 获取权重和偏置
w_hat = lasso_model.coef_[0]
b_hat = lasso_model.intercept_
print(f"Lasso 回归预测权重: {w_hat:.2f}, 预测偏置: {b_hat:.2f}")
# 3. 结果
y_pred_lasso = lasso_model.predict(X)
总结
模型 | 工具 | 正则化类型 | 特点 |
---|---|---|---|
普通线性回归 | Scikit-learn | 无 | 不限制参数,适合无噪声或低维数据场景。 |
Ridge 回归 | Scikit-learn | L2 正则化 | 限制权重大小,使模型更平滑,适合高维场景。 |
Lasso 回归 | Scikit-learn | L1 正则化 | 特征选择效果好,可使部分特征权重为 0。 |
自定义线性回归 | PyTorch | 支持梯度下降 | 灵活性高,可扩展到复杂深度学习任务。 |
文章参考
- 《机器学习(西瓜书)》
- 部分LaTeX 公式借助了AI的帮助