《什么是线性回归?从原理到代码,彻底搞懂》
作者:Weisian
发布时间:2026年3月

为什么线性回归是机器学习的“Hello World”?
你是不是觉得机器学习高深莫测,满脑子都是神经网络、Transformer、大模型?
但我想告诉你:所有复杂的模型,都始于一个简单的直线方程。
线性回归(Linear Regression)不仅是统计学中最经典的算法,更是机器学习大厦的基石。它简单、直观、可解释性强,更重要的是——它蕴含了机器学习最核心的思想:通过数据学习规律,用损失函数衡量误差,用优化算法寻找最优解。

如果你能彻底搞懂线性回归,你就掌握了打开机器学习大门的钥匙。今天,我不讲枯燥的数学推导,而是带你从直观理解 → 核心公式 → 手撕代码 → sklearn实战 → 可视化验证,一步步把线性回归吃透。
第一部分:先搞懂:线性回归到底在做什么?
1.1 一个生活化的类比:预测房价
想象一下,你想买房子,手头有一组数据:
- 房屋面积(平方米):50, 60, 70, 80, 90…
- 对应房价(万元):150, 180, 210, 240, 270…
你发现:面积越大,房价越高,而且大致呈一条直线关系。
于是你画了一条直线,试图用这条直线去预测任意面积对应的房价。

这就是线性回归在做的事:找到一条最佳拟合直线,让预测值尽可能接近真实值。
1.2 线性回归的核心思想
线性回归假设目标变量 yyy 和特征变量 xxx 之间存在线性关系:
y=w⋅x+b
y = w \\cdot x + b
y=w⋅x+b
其中:
- yyy:预测值(如房价)
- xxx:输入特征(如面积)
- www:权重(斜率,表示xxx对yyy的影响程度)
- bbb:偏置(截距,当x=0x=0x=0时的基础值)
我们的任务就是:从数据中学习出最佳的 www 和 bbb,使得预测误差最小。

1.3 线性回归要解决的两个核心问题
接下来,我们逐一拆解。
第二部分:核心原理——从公式到直观理解
2.1 损失函数:如何衡量预测误差?
我们需要一个指标来判断直线拟合的效果,这就是损失函数(Loss Function)。
直观理解:
对于每个数据点,预测值和真实值之间会有误差:
误差 = 真实值 – 预测值 = y_true – y_pred
我们希望所有数据点的误差总和最小。
最常用的损失函数是均方误差(MSE, Mean Squared Error):
MSE=1n∑i=1n(yi−y^i)2
\\text{MSE} = \\frac{1}{n} \\sum_{i=1}^{n} (y_i – \\hat{y}_i)^2
MSE=n1i=1∑n(yi−y^i)2
其中:
- yiy_iyi:真实值
- y^i=w⋅xi+b\\hat{y}_i = w \\cdot x_i + by^i=w⋅xi+b:预测值
- nnn:样本数量
线性回归的目标:找到一组w和b,让MSE最小。

直观理解:
MSE计算的是"预测值与真实值差的平方的平均值"。
- 差得越远,平方后惩罚越大
- 我们希望MSE越小越好
找到最小MSE的过程,就是"优化"。我们有两种核心方法:最小二乘法和梯度下降。
2.2 最小二乘法:解析解的直接求解
最小二乘法(Least Squares)的思想很简单:找到一组 www 和 bbb,使得MSE最小。过程基本就是对MSE求导,令导数为0,直接解出w和b的解析解。
对于一元线性回归,最小二乘法有解析解(可以直接用公式算出来):
w=∑i=1n(xi−xˉ)(yi−yˉ)∑i=1n(xi−xˉ)2
w = \\frac{\\sum_{i=1}^{n} (x_i – \\bar{x})(y_i – \\bar{y})}{\\sum_{i=1}^{n} (x_i – \\bar{x})^2}
w=∑i=1n(xi−xˉ)2∑i=1n(xi−xˉ)(yi−yˉ)
b=yˉ−w⋅xˉ
b = \\bar{y} – w \\cdot \\bar{x}
b=yˉ−w⋅xˉ
其中 xˉ\\bar{x}xˉ 和 yˉ\\bar{y}yˉ 分别是 xxx 和 yyy 的平均值。
优点:计算快,一次搞定
缺点:只适用于简单线性回归,复杂模型无法用解析解

2.3 梯度下降:迭代优化的通用方法
当模型变复杂(比如多元线性回归、神经网络),解析解就不存在了。这时我们需要梯度下降(Gradient Descent)。
核心思想:
想象你站在山上,想走到最低点(损失最小)。你每次往最陡的下坡方向走一小步,重复这个过程,最终到达谷底。
求解过程:
α(学习率):每一步走多远
- α太大:步子太大,可能错过最低点
- α太小:收敛太慢,浪费计算资源
优点:适合高维数据,可扩展性强
缺点:需要调参(学习率、迭代次数)
数学表达:
w:=w−α⋅∂MSE∂w
w := w – \\alpha \\cdot \\frac{\\partial \\text{MSE}}{\\partial w}
w:=w−α⋅∂w∂MSE
b:=b−α⋅∂MSE∂b
b := b – \\alpha \\cdot \\frac{\\partial \\text{MSE}}{\\partial b}
b:=b−α⋅∂b∂MSE
其中:
- α\\alphaα:学习率(步长,太大容易 overshoot,太小收敛慢)
- ∂MSE∂w\\frac{\\partial \\text{MSE}}{\\partial w}∂w∂MSE:MSE对www的偏导数(梯度)
直观理解:
- 梯度告诉我们应该往哪个方向调整参数
- 学习率决定我们走多大步
- 反复迭代,直到损失不再明显下降

2.4 核心概念对比
| 最小二乘法 | 数学公式直接求解 | 特征少(<1000) | 计算快、结果精确 | 高维数据计算复杂 |
| 梯度下降 | 迭代优化 | 特征多(>1000) | 通用性强、易实现 | 需要调参、收敛慢 |

第三部分:实战演练——从零实现线性回归
环境准备
pip install numpy pandas matplotlib scikit-learn
3.1 第一步:生成模拟数据
我们用代码生成一组"面积-房价"的模拟数据,方便演示。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
# 设置中文字体(Windows)
# 如果是在Mac或Linux下运行,可能需要改为 'Arial Unicode MS' 或 'WenQuanYi Micro Hei'
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置随机种子,确保结果可复现
np.random.seed(42)
# 生成模拟数据:y = 3x + 5 + 噪声
X = 2 * np.random.rand(100, 1) # 面积:0-2之间
y = 3 * X + 5 + np.random.randn(100, 1) # 房价:3*面积+5+噪声
print(f"数据形状: X={X.shape}, y={y.shape}")
print(f"前5个样本:\\nX={X[:5].flatten()}\\ny={y[:5].flatten()}")
# 可视化原始数据
plt.figure(figsize=(8, 6))
plt.scatter(X, y, alpha=0.6, label='原始数据')
plt.xlabel('房屋面积 (x)')
plt.ylabel('房价 (y)')
plt.title('模拟房屋面积与房价关系')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
运行结果:

运行结果分析:
- 生成了100个样本点
- 真实关系是 y=3x+5y = 3x + 5y=3x+5,但加了随机噪声
- 散点图显示大致呈线性趋势
3.2 第二步:手撕最小二乘法(解析解)
我们自己实现最小二乘法公式,不依赖sklearn。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
# 设置中文字体(Windows)
# 如果是在Mac或Linux下运行,可能需要改为 'Arial Unicode MS' 或 'WenQuanYi Micro Hei'
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置随机种子,确保结果可复现
np.random.seed(42)
# 生成模拟数据:y = 3x + 5 + 噪声
X = 2 * np.random.rand(100, 1) # 面积:0-2之间
y = 3 * X + 5 + np.random.randn(100, 1) # 房价:3*面积+5+噪声
print("\\n" + "="*70)
print("📌 方法一:手撕最小二乘法(解析解)")
print("="*70)
# 计算均值
x_mean = X.mean()
y_mean = y.mean()
# 计算分子和分母
# 注意:np.sum 返回的是标量 (scalar)
numerator = np.sum((X – x_mean) * (y – y_mean))
denominator = np.sum((X – x_mean) ** 2)
# 计算 w 和 b
w_ls = numerator / denominator # 这里 w_ls 是一个标量 (float),不再是数组
b_ls = y_mean – w_ls * x_mean # 这里 b_ls 也是一个标量
# 【修复点】:直接打印标量,不要使用 [0][0] 索引
print(f"最小二乘法结果:")
print(f" w (斜率) = {w_ls:.4f}")
print(f" b (截距) = {b_ls:.4f}")
print(f" 拟合方程: y = {w_ls:.4f} * x + {b_ls:.4f}")
# 预测
# numpy 支持标量与数组直接运算,无需 reshape
y_pred_ls = w_ls * X + b_ls
# 评估
mse_ls = mean_squared_error(y, y_pred_ls)
r2_ls = r2_score(y, y_pred_ls)
print(f" MSE: {mse_ls:.4f}")
print(f" R²: {r2_ls:.4f}")
# 可视化
plt.figure(figsize=(8, 6))
plt.scatter(X, y, alpha=0.6, label='原始数据')
# 绘制拟合线,因为 X 是有序的或者散乱的,plot 会按 X 的顺序连线
# 为了线条平滑,通常建议对 X 排序后绘制,但这里直接用原数据也能画出折线效果
# 如果想画直线,可以取最小和最大X值来计算两端点
x_line = np.linspace(X.min(), X.max(), 100).reshape(–1, 1)
y_line = w_ls * x_line + b_ls
plt.plot(x_line, y_line, 'r-', linewidth=2, label=f'最小二乘法拟合\\ny={w_ls:.2f}x+{b_ls:.2f}')
plt.xlabel('房屋面积 (x)')
plt.ylabel('房价 (y)')
plt.title('最小二乘法拟合效果')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
运行结果:
======================================================================
📌 方法一:手撕最小二乘法(解析解)
======================================================================
最小二乘法结果:
w (斜率) = 2.7701
b (截距) = 5.2151
拟合方程: y = 2.7701 * x + 5.2151
MSE: 0.8066
R²: 0.7693

关键观察:
- 学到的 w≈3w \\approx 3w≈3,b≈5b \\approx 5b≈5,非常接近真实值
- R²=0.77,说明模型解释了77%的方差,拟合效果还可以
3.3 第三步:手撕梯度下降(迭代优化)
现在我们用梯度下降法,从零开始迭代优化。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
# 设置中文字体(Windows)
# 如果是在Mac或Linux下运行,可能需要改为 'Arial Unicode MS' 或 'WenQuanYi Micro Hei'
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置随机种子,确保结果可复现
np.random.seed(42)
# 生成模拟数据:y = 3x + 5 + 噪声
X = 2 * np.random.rand(100, 1) # 面积:0-2之间
y = 3 * X + 5 + np.random.randn(100, 1) # 房价:3*面积+5+噪声
print("\\n" + "="*70)
print("📌 方法二:手撕梯度下降(迭代优化)")
print("="*70)
# 初始化参数
w_gd = np.random.randn(1, 1)
b_gd = np.random.randn(1, 1)
# 超参数
learning_rate = 0.1
n_iterations = 1000
m = len(X) # 样本数量
# 记录损失变化
loss_history = []
for iteration in range(n_iterations):
# 预测
y_pred = w_gd * X + b_gd
# 计算梯度
dw = (2/m) * np.dot(X.T, (y_pred – y))
db = (2/m) * np.sum(y_pred – y)
# 更新参数
w_gd = w_gd – learning_rate * dw
b_gd = b_gd – learning_rate * db
# 计算当前损失
mse = np.mean((y_pred – y) ** 2)
loss_history.append(mse)
if iteration % 100 == 0:
print(f"迭代 {iteration}: MSE = {mse:.4f}, w = {w_gd[0][0]:.4f}, b = {b_gd[0][0]:.4f}")
print(f"\\n梯度下降最终结果:")
print(f" w (斜率) = {w_gd[0][0]:.4f}")
print(f" b (截距) = {b_gd[0][0]:.4f}")
print(f" 拟合方程: y = {w_gd[0][0]:.4f} * x + {b_gd[0][0]:.4f}")
# 预测
y_pred_gd = w_gd * X + b_gd
# 评估
mse_gd = mean_squared_error(y, y_pred_gd)
r2_gd = r2_score(y, y_pred_gd)
print(f" MSE: {mse_gd:.4f}")
print(f" R²: {r2_gd:.4f}")
# 可视化1:拟合效果
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(X, y, alpha=0.6, label='原始数据')
plt.plot(X, y_pred_gd, 'g-', linewidth=2, label=f'梯度下降拟合\\ny={w_gd[0][0]:.2f}x+{b_gd[0][0]:.2f}')
plt.xlabel('房屋面积 (x)')
plt.ylabel('房价 (y)')
plt.title('梯度下降拟合效果')
plt.legend()
plt.grid(True, alpha=0.3)
# 可视化2:损失下降曲线
plt.subplot(1, 2, 2)
plt.plot(loss_history)
plt.xlabel('迭代次数')
plt.ylabel('MSE损失')
plt.title('梯度下降损失收敛过程')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
运行结果:
======================================================================
📌 方法二:手撕梯度下降(迭代优化)
======================================================================
迭代 0: MSE = 43.8471, w = 1.4013, b = 2.7244
迭代 100: MSE = 0.8068, w = 2.7902, b = 5.1923
迭代 200: MSE = 0.8066, w = 2.7708, b = 5.2144
迭代 300: MSE = 0.8066, w = 2.7701, b = 5.2151
迭代 400: MSE = 0.8066, w = 2.7701, b = 5.2151
迭代 500: MSE = 0.8066, w = 2.7701, b = 5.2151
迭代 600: MSE = 0.8066, w = 2.7701, b = 5.2151
迭代 700: MSE = 0.8066, w = 2.7701, b = 5.2151
迭代 800: MSE = 0.8066, w = 2.7701, b = 5.2151
迭代 900: MSE = 0.8066, w = 2.7701, b = 5.2151
梯度下降最终结果:
w (斜率) = 2.7701
b (截距) = 5.2151
拟合方程: y = 2.7701 * x + 5.2151
MSE: 0.8066
R²: 0.7693

关键观察:
- 梯度下降经过约1000次迭代后收敛
- 最终结果与最小二乘法几乎一致
- 损失曲线显示MSE快速下降后趋于平稳
3.4 第四步:sklearn实现(一行代码搞定)
实际工作中,我们直接用sklearn,省时省力。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
# 设置中文字体(Windows)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置随机种子
np.random.seed(42)
# 生成模拟数据
X = 2 * np.random.rand(100, 1)
y = 3 * X + 5 + np.random.randn(100, 1)
# — 方法一:最小二乘法 —
x_mean = X.mean()
y_mean = y.mean()
numerator = np.sum((X – x_mean) * (y – y_mean))
denominator = np.sum((X – x_mean) ** 2)
w_ls = numerator / denominator # 标量
b_ls = y_mean – w_ls * x_mean # 标量
y_pred_ls = w_ls * X + b_ls
mse_ls = mean_squared_error(y, y_pred_ls)
r2_ls = r2_score(y, y_pred_ls)
# — 方法二:梯度下降 —
w_gd = np.random.randn(1, 1)
b_gd = np.random.randn(1, 1)
learning_rate = 0.1
n_iterations = 1000
m = len(X)
loss_history = []
for iteration in range(n_iterations):
y_pred = w_gd * X + b_gd
dw = (2/m) * np.dot(X.T, (y_pred – y))
db = (2/m) * np.sum(y_pred – y)
w_gd = w_gd – learning_rate * dw
b_gd = b_gd – learning_rate * db
mse = np.mean((y_pred – y) ** 2)
loss_history.append(mse)
y_pred_gd = w_gd * X + b_gd
mse_gd = mean_squared_error(y, y_pred_gd)
r2_gd = r2_score(y, y_pred_gd)
# — 方法三:sklearn —
model = LinearRegression()
model.fit(X, y)
w_sklearn = model.coef_[0][0]
b_sklearn = model.intercept_[0] # 注意:新版sklearn intercept_可能是标量,旧版是数组,这里兼容处理
if isinstance(b_sklearn, np.ndarray):
b_sklearn = b_sklearn[0]
y_pred_sklearn = model.predict(X)
mse_sklearn = mean_squared_error(y, y_pred_sklearn)
r2_sklearn = r2_score(y, y_pred_sklearn)
# — 打印对比表格 (修复点在这里) —
print("\\n" + "="*70)
print("📊 三种方法结果对比")
print("="*70)
print(f"{'方法':<15} {'w (斜率)':<12} {'b (截距)':<12} {'MSE':<10} {'R²':<10}")
print("-"*60)
# 【修复】:直接使用变量名,不要加 [0][0],因为 w_ls 和 b_ls 已经是标量了
print(f"{'最小二乘法':<15} {w_ls:<12.4f} {b_ls:<12.4f} {mse_ls:<10.4f} {r2_ls:<10.4f}")
# 梯度下降的结果 w_gd 和 b_gd 仍然是数组 (1,1),所以保留 [0][0]
print(f"{'梯度下降':<15} {w_gd[0][0]:<12.4f} {b_gd[0][0]:<12.4f} {mse_gd:<10.4f} {r2_gd:<10.4f}")
# sklearn 的结果我们上面已经提取为标量了
print(f"{'sklearn':<15} {w_sklearn:<12.4f} {b_sklearn:<12.4f} {mse_sklearn:<10.4f} {r2_sklearn:<10.4f}")
print("="*60)
print("✅ 三种方法结果高度一致!")
运行结果:
======================================================================
📊 三种方法结果对比
======================================================================
方法 w (斜率) b (截距) MSE R²
————————————————————
最小二乘法 2.7701 5.2151 0.8066 0.7693
梯度下降 2.7701 5.2151 0.8066 0.7693
sklearn 2.7701 5.2151 0.8066 0.7693
============================================================
✅ 三种方法结果高度一致!
第四部分:进阶——多元线性回归实战
现实世界中,影响房价的不只是面积,还有房龄、地段、楼层等多个因素。这就是多元线性回归。
4.1 多元线性回归公式
y=w1⋅x1+w2⋅x2+…+wn⋅xn+b
y = w_1 \\cdot x_1 + w_2 \\cdot x_2 + … + w_n \\cdot x_n + b
y=w1⋅x1+w2⋅x2+…+wn⋅xn+b
写成矩阵形式:
y=X⋅w+b
\\mathbf{y} = \\mathbf{X} \\cdot \\mathbf{w} + b
y=X⋅w+b
4.2 实战代码:预测波士顿房价(简化版)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
# 设置中文字体(Windows)
# 如果是在Mac或Linux下运行,可能需要改为 'Arial Unicode MS' 或 'WenQuanYi Micro Hei'
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
print("\\n" + "="*70)
print("📌 进阶:多元线性回归实战")
print("="*70)
# 加载糖尿病数据集(替代波士顿房价,因为波士顿数据集已被弃用)
diabetes = load_diabetes()
X_multi = diabetes.data # 10个特征
y_multi = diabetes.target # 疾病进展指标
print(f"数据集形状: X={X_multi.shape}, y={y_multi.shape}")
print(f"特征名称: {diabetes.feature_names}")
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X_multi, y_multi, test_size=0.2, random_state=42
)
print(f"训练集: {X_train.shape}, 测试集: {X_test.shape}")
# 训练模型
model_multi = LinearRegression()
model_multi.fit(X_train, y_train)
# 预测
y_train_pred = model_multi.predict(X_train)
y_test_pred = model_multi.predict(X_test)
# 评估
train_mse = mean_squared_error(y_train, y_train_pred)
test_mse = mean_squared_error(y_test, y_test_pred)
train_r2 = r2_score(y_train, y_train_pred)
test_r2 = r2_score(y_test, y_test_pred)
print(f"\\n多元线性回归结果:")
print(f" 训练集 MSE: {train_mse:.2f}, R²: {train_r2:.4f}")
print(f" 测试集 MSE: {test_mse:.2f}, R²: {test_r2:.4f}")
print(f"\\n学到的权重系数:")
for i, (name, coef) in enumerate(zip(diabetes.feature_names, model_multi.coef_)):
print(f" {name}: {coef:.4f}")
print(f" 截距 b: {model_multi.intercept_:.4f}")
# 可视化:真实值 vs 预测值
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.scatter(y_train, y_train_pred, alpha=0.6)
plt.plot([y_train.min(), y_train.max()], [y_train.min(), y_train.max()], 'r–', linewidth=2)
plt.xlabel('真实值 (训练集)')
plt.ylabel('预测值 (训练集)')
plt.title('训练集:真实值 vs 预测值')
plt.grid(True, alpha=0.3)
plt.subplot(1, 2, 2)
plt.scatter(y_test, y_test_pred, alpha=0.6, color='orange')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r–', linewidth=2)
plt.xlabel('真实值 (测试集)')
plt.ylabel('预测值 (测试集)')
plt.title('测试集:真实值 vs 预测值')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
运行结果:
======================================================================
📌 进阶:多元线性回归实战
======================================================================
数据集形状: X=(442, 10), y=(442,)
特征名称: ['age', 'sex', 'bmi', 'bp', 's1', 's2', 's3', 's4', 's5', 's6']
训练集: (353, 10), 测试集: (89, 10)
多元线性回归结果:
训练集 MSE: 2868.55, R²: 0.5279
测试集 MSE: 2900.19, R²: 0.4526
学到的权重系数:
age: 37.9040
sex: -241.9644
bmi: 542.4288
bp: 347.7038
s1: -931.4888
s2: 518.0623
s3: 163.4200
s4: 275.3179
s5: 736.1989
s6: 48.6707
截距 b: 151.3456

运行结果分析:
- 多元线性回归同时考虑10个特征
- 训练集R²约0.52,测试集R²约0.45,有一定泛化能力
- 散点图越靠近对角线,预测越准确
第五部分:完整的线性回归代码模板
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
# 设置中文字体(Windows)
# 如果是在Mac或Linux下运行,可能需要改为 'Arial Unicode MS' 或 'WenQuanYi Micro Hei'
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def linear_regression_demo():
print("="*70)
print("🚀 线性回归完整流程演示")
print("="*70)
# 1. 生成/加载数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 3 * X + 5 + np.random.randn(100, 1)
# 2. 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3. 训练模型
model = LinearRegression()
model.fit(X_train, y_train)
# 4. 预测
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
# 5. 评估
train_mse = mean_squared_error(y_train, y_train_pred)
test_mse = mean_squared_error(y_test, y_test_pred)
train_r2 = r2_score(y_train, y_train_pred)
test_r2 = r2_score(y_test, y_test_pred)
print(f"\\n模型参数:")
print(f" w = {model.coef_[0][0]:.4f}")
print(f" b = {model.intercept_[0]:.4f}")
print(f"\\n评估结果:")
print(f" 训练集 MSE: {train_mse:.4f}, R²: {train_r2:.4f}")
print(f" 测试集 MSE: {test_mse:.4f}, R²: {test_r2:.4f}")
# 6. 可视化
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(X_train, y_train, alpha=0.6, label='训练数据')
plt.scatter(X_test, y_test, alpha=0.6, label='测试数据', color='orange')
plt.plot(X, model.predict(X), 'r-', linewidth=2, label='拟合直线')
plt.xlabel('x')
plt.ylabel('y')
plt.title('线性回归拟合效果')
plt.legend()
plt.grid(True, alpha=0.3)
plt.subplot(1, 2, 2)
plt.scatter(y_test, y_test_pred, alpha=0.6)
plt.plot([y_test.min(), y_test.max()],
[y_test.min(), y_test.max()], 'r–', linewidth=2)
plt.xlabel('真实值')
plt.ylabel('预测值')
plt.title('测试集:真实值 vs 预测值')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
if __name__ == "__main__":
linear_regression_demo()
运行结果:
======================================================================
🚀 线性回归完整流程演示
======================================================================
模型参数:
w = 2.7993
b = 5.1429
评估结果:
训练集 MSE: 0.8477, R²: 0.7582
测试集 MSE: 0.6537, R²: 0.8072

第六部分:常见问题与解答
Q1:线性回归只能处理直线关系吗?
A: 不是!通过特征变换,线性回归可以拟合曲线。
# 例子:拟合抛物线
X = np.random.uniform(–3, 3, 100)
y = X**2 + np.random.randn(100) * 0.5
# 添加平方特征
X_poly = np.column_stack([X, X**2])
model = LinearRegression()
model.fit(X_poly, y)
print(f"学习到的关系: y = {model.coef_[0]:.2f}x + {model.coef_[1]:.2f}x² + {model.intercept_:.2f}")
Q2:什么时候不能用线性回归?
Q3:R²是什么意思?
**R²(决定系数)**表示模型解释了目标变量多少方差:
- R²=1:完美拟合
- R²=0:不如直接用平均值
- R²<0:比直接用平均值还差
Q4:梯度下降的学习率怎么选?
- 太大:可能震荡不收敛
- 太小:收敛太慢
- 常用值:0.01、0.001、0.0001,可以试试逐步衰减

写在最后:线性回归教会我们的事
线性回归看似简单,但它蕴含了机器学习的三大核心思想:
这些思想,在深度学习、强化学习等高级模型中依然适用。学好线性回归,不是终点,而是起点。

📌 核心要点回顾
- 最小二乘法:解析解,适合简单模型
- 梯度下降:迭代优化,适合复杂模型
- MSE:平均平方误差
- R²:决定系数,越接近1越好
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
- 一定要划分训练集和测试集
- 关注R²和MSE,判断模型好坏
- 可视化帮助理解模型表现

下一步学习建议:
- ✅ 搞懂线性回归后,可以学习**正则化(Ridge/Lasso)**防止过拟合
- ✅ 然后进入逻辑回归,解决分类问题
- ✅ 再逐步深入决策树、随机森林、神经网络
记住:所有复杂的模型,都始于一条简单的直线。
希望这篇实战指南对你有帮助!所有代码都可以直接复制运行。如果你有任何问题,欢迎在评论区留言讨论!



