多项式回归:当线性模型“跑不动”时,给特征“升个级”就能搞定非线性数据!

线性回归能解决很多问题,但面对“弯曲”的数据时就束手无策了——比如房价和面积的关系:小面积时房价增长慢,中等面积增长快,大面积又趋缓(呈二次曲线);再比如植物生长速度和时间的关系:前期慢、中期快、后期又变慢(呈S型曲线)。

这时候,多项式回归就能“救场”:它通过给特征“升次”(比如添加x²、x³项),让线性模型摇身一变,能拟合各种弯曲的非线性关系。今天从原理到代码,手把手教你用多项式回归搞定非线性数据,附公式推导和避坑指南!

一、为什么线性回归会“失灵”?看个扎心对比

假设我们有一组数据:y随x的变化是“先增后减”的二次曲线(比如抛射体的高度与时间的关系)。用线性回归和多项式回归分别拟合,结果天差地别:

  • 线性回归:只能画一条直线,不管怎么调,都无法贴合曲线趋势,误差很大;
  • 多项式回归:通过添加x²项,拟合出一条抛物线,完美贴合数据的弯曲趋势。

核心问题:线性回归的模型是y = w₀ + w₁x(一次函数),只能表达直线关系;而现实中,很多变量间的关系是弯曲的(二次、三次甚至更高次),这时候就需要给特征“升次”。

二、多项式回归:给特征“加项”,让线性模型“曲线救国”

1. 原理:用“高次项”给模型“装弯道”

多项式回归的思路特别简单:给原始特征添加高次项(如x²、x³),再用线性回归拟合这些“扩展后的特征”

比如,对于特征x:

  • 线性回归模型:y=w0+w1x+εy = w_0 + w_1x + \varepsilony=w0+w1x+ε(只能拟合直线);
  • 二次多项式回归:y=w0+w1x+w2x2+εy = w_0 + w_1x + w_2x^2 + \varepsilony=w0+w1x+w2x2+ε(能拟合抛物线);
  • 三次多项式回归:y=w0+w1x+w2x2+w3x3+εy = w_0 + w_1x + w_2x^2 + w_3x^3 + \varepsilony=w0+w1x+w2x2+w3x3+ε(能拟合更复杂的曲线)。

这里的“多项式”指的是对特征x的次数,而模型对参数(w₀、w₁、w₂…)依然是线性的——所以多项式回归本质是“线性回归的扩展”,能用线性回归的求解方法(如最小二乘法)计算参数。

2. 核心公式:从“直线”到“曲线”的数学表达

(1)多项式特征扩展

对于原始特征xxxddd次多项式的扩展特征为:
ϕ(x)=[1,x,x2,x3,...,xd]\phi(x) = [1, x, x^2, x^3, ..., x^d]ϕ(x)=[1,x,x2,x3,...,xd]

比如d=2d=2d=2(二次)时,扩展特征是[1,x,x2][1, x, x^2][1,x,x2]d=3d=3d=3(三次)时,是[1,x,x2,x3][1, x, x^2, x^3][1,x,x2,x3]

(2)多项式回归模型

用扩展后的特征拟合目标yyy,模型为:
y^=w0⋅1+w1⋅x+w2⋅x2+...+wd⋅xd\hat{y} = w_0 \cdot 1 + w_1 \cdot x + w_2 \cdot x^2 + ... + w_d \cdot x^dy^=w01+w1x+w2x2+...+wdxd

用矩阵表示(更简洁):
y^=ϕ(x)⋅W\hat{y} = \phi(x) \cdot Wy^=ϕ(x)W

其中W=[w0,w1,...,wd]TW = [w_0, w_1, ..., w_d]^TW=[w0,w1,...,wd]T是参数向量,ϕ(x)\phi(x)ϕ(x)是扩展特征向量。

(3)参数求解(最小二乘法)

和线性回归一样,通过最小化“预测值与真实值的平方差”求解参数WWW
min⁡W∑i=1n(y^i−yi)2=min⁡W∣∣ΦW−Y∣∣2\min_W \sum_{i=1}^n (\hat{y}_i - y_i)^2 = \min_W ||\Phi W - Y||^2Wmini=1n(y^iyi)2=Wmin∣∣ΦWY2

其中Φ\PhiΦ是所有样本的扩展特征矩阵(每行是一个样本的ϕ(xi)\phi(x_i)ϕ(xi)),YYY是真实值向量。求解后得到:
W=(ΦTΦ)−1ΦTYW = (\Phi^T \Phi)^{-1} \Phi^T YW=(ΦTΦ)1ΦTY

三、代码实战:用二次多项式回归拟合“抛物线”数据

我们生成一组二次函数数据(带噪声),完整演示多项式回归的流程:特征扩展→模型训练→评估→可视化。

完整代码(可直接运行)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures  # 多项式特征扩展工具
from sklearn.linear_model import LinearRegression     # 线性回归(多项式回归的基础)
from sklearn.model_selection import train_test_split  # 拆分训练集和测试集
from sklearn.metrics import mean_squared_error, r2_score  # 评估指标

# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False  # 负号正常显示


# ----------------------
# 1. 生成非线性数据(二次函数+噪声)
# ----------------------
np.random.seed(42)  # 固定随机种子,结果可复现
x = np.random.rand(1000, 1) * 10  # 原始特征x:0-10之间的随机数(1000个样本)
# 真实关系:y = 2 + 1.5x + x²(二次函数),加噪声模拟真实数据
y = 2 + 1.5 * x + x**2 + np.random.normal(0, 5, size=x.shape)  # 噪声标准差5

# 转为DataFrame,方便查看
data = pd.DataFrame({'x': x.flatten(), 'y': y.flatten()})
print("前5行数据:")
print(data.head())


# ----------------------
# 2. 拆分数据+多项式特征扩展
# ----------------------
# 拆分训练集(80%)和测试集(20%)
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)

# 多项式特征扩展:将x扩展为[x, x²](degree=2表示二次)
poly = PolynomialFeatures(degree=2, include_bias=False)  # include_bias=False:不自动加常数项(后续线性回归会加)
X_train_poly = poly.fit_transform(X_train)  # 训练集扩展:形状(800, 2),每行为[x, x²]
X_test_poly = poly.transform(X_test)        # 测试集扩展(用训练集的规则)


# ----------------------
# 3. 训练多项式回归模型(本质是线性回归)
# ----------------------
# 用线性回归拟合扩展后的特征(此时模型是y = w0 + w1x + w2x²)
model = LinearRegression()
model.fit(X_train_poly, y_train)

# 查看模型参数(w0是截距,w1对应x,w2对应x²)
print(f"\n模型参数:截距w0 = {model.intercept_[0]:.2f}")
print(f"x的系数w1 = {model.coef_[0][0]:.2f},x²的系数w2 = {model.coef_[0][1]:.2f}")
# 对比真实关系(y=2+1.5x+x²),参数应接近2、1.5、1


# ----------------------
# 4. 模型评估:训练集vs测试集
# ----------------------
# 预测
y_train_pred = model.predict(X_train_poly)  # 训练集预测
y_test_pred = model.predict(X_test_poly)    # 测试集预测

# 计算评估指标
train_rmse = np.sqrt(mean_squared_error(y_train, y_train_pred))  # 训练集均方根误差
test_rmse = np.sqrt(mean_squared_error(y_test, y_test_pred))      # 测试集均方根误差
train_r2 = r2_score(y_train, y_train_pred)  # 训练集R²(越接近1越好)
test_r2 = r2_score(y_test, y_test_pred)      # 测试集R²

print(f"\n训练集:RMSE = {train_rmse:.2f},R² = {train_r2:.2f}")
print(f"测试集:RMSE = {test_rmse:.2f},R² = {test_r2:.2f}")  # 若两者接近,说明模型泛化好


# ----------------------
# 5. 可视化:从图中看拟合效果
# ----------------------
# 图1:数据点与多项式拟合曲线
plt.figure(figsize=(10, 6))
plt.scatter(x, y, color='blue', alpha=0.5, label='原始数据点')  # 所有数据点
# 排序x,让拟合曲线更平滑
x_sorted = np.sort(x, axis=0)
y_pred_sorted = model.predict(poly.transform(x_sorted))  # 排序后的预测值
plt.plot(x_sorted, y_pred_sorted, color='red', linewidth=3, label='二次多项式拟合曲线')
plt.xlabel('x')
plt.ylabel('y')
plt.title('原始数据与多项式回归拟合曲线', fontsize=14)
plt.legend()
plt.show()

# 图2:残差图(看误差是否随机,判断模型是否合适)
plt.figure(figsize=(10, 6))
plt.scatter(y_train, y_train - y_train_pred, color='blue', alpha=0.5, label='训练集残差')
plt.scatter(y_test, y_test - y_test_pred, color='red', alpha=0.5, label='测试集残差')
plt.hlines(0, y.min(), y.max(), color='black', linestyle='--')  # 参考线:残差=0
plt.xlabel('实际y值')
plt.ylabel('残差(实际-预测)')
plt.title('残差图(残差应随机分布在0附近)', fontsize=14)
plt.legend()
plt.show()

# 图3:实际值vs预测值(越接近对角线,预测越准)
plt.figure(figsize=(10, 6))
plt.scatter(y_train, y_train_pred, color='blue', alpha=0.5, label='训练集')
plt.scatter(y_test, y_test_pred, color='red', alpha=0.5, label='测试集')
plt.plot([y.min(), y.max()], [y.min(), y.max()], color='black', linestyle='--')  # 理想对角线
plt.xlabel('实际y值')
plt.ylabel('预测y值')
plt.title('实际值 vs 预测值', fontsize=14)
plt.legend()
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、结果解读:从图中看懂多项式回归的“魔力”

1. 拟合曲线:直线变曲线,完美贴合数据

第一个图中,蓝色点是原始数据(明显呈抛物线分布),红色线是二次多项式回归的拟合曲线。可以看到:

  • 曲线精准“跟踪”了数据的弯曲趋势,从左下到右上先缓后陡(符合二次函数特征);
  • 这是线性回归(直线)做不到的——如果用线性回归,拟合线会是一条斜向上的直线,与大部分数据点偏离很远。

2. 残差图:误差是否“随机”,决定模型是否合适

第二个图是残差(实际值-预测值)的分布:

  • 残差整体围绕0值随机散布,没有明显的趋势(比如没有全正或全负的区域);
  • 训练集和测试集的残差分布接近,说明模型没有过拟合(过拟合时测试集残差会明显更大)。

残差图的作用:如果残差呈某种规律(比如呈曲线),说明模型还没捕捉到所有特征(比如需要更高次的多项式)。

3. 实际vs预测:越靠近对角线,预测越准

第三个图中,所有点都密集分布在黑色对角线上(y_pred = y_actual):

  • 这说明预测值和实际值非常接近,模型的误差很小;
  • 训练集和测试集的点混合在一起,没有明显分离,进一步证明模型泛化能力好。

五、避坑指南:多项式回归的“甜蜜点”与“雷区”

1. 次数不是越高越好!警惕“过拟合”

多项式的次数(degree)越高,曲线越“灵活”,但也越容易“过度贴合噪声”:

  • 比如用10次多项式拟合二次数据,曲线会剧烈波动(像“心电图”),虽然训练集误差几乎为0,但测试集误差会很大(过拟合);
  • 建议:从低次(2-3次)开始尝试,用“学习曲线”或测试集误差判断最优次数(误差开始增大时及时停止)。

2. 特征缩放不能少!高次项容易“数值爆炸”

x的高次项(如x⁵、x¹⁰)会导致数值非常大(比如x=10时,x¹⁰=100亿),可能让模型参数计算不稳定。
解决办法:扩展多项式特征前,先对原始特征做标准化(Z-Score),将x缩放到均值0、标准差1的范围,避免高次项数值过大。

3. 不是所有非线性关系都适合多项式

多项式回归适合“轻度非线性”数据(比如明确的二次、三次关系),但面对复杂非线性(如分段函数、突变点),效果不如决策树、神经网络:

  • 比如股票价格的“断崖式下跌”,多项式回归可能会“预测过头”(因为它的曲线是连续光滑的);
  • 这时候更适合用树模型(能处理不连续关系)。

总结:多项式回归的“最佳适用场景”

多项式回归是处理非线性数据的“轻量级方案”,核心价值是:用简单的线性回归框架,解决中等复杂度的非线性问题

当你遇到以下情况,优先考虑多项式回归:

  • 数据呈现明显的曲线趋势(如二次、三次关系),且趋势光滑(无突变);
  • 希望模型简单易解释(多项式回归的参数可直接对应特征的贡献,比如w2是x²的系数);
  • 特征维度低(通常是1-2个特征,高维特征用多项式会导致维度爆炸)。

记住:多项式回归的关键是找到“合适的次数”——既不过于简单(欠拟合),也不过于复杂(过拟合)。这个“甜蜜点”,就是多项式回归的精髓。

你在项目中用过多项式回归吗?遇到过哪些有趣的非线性数据?评论区聊聊~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值