直接用linearregression拟合非线性关系会导致欠拟合,需通过polynomialfeatures显式扩展特征;必须配合standardscaler标准化,且整个流程须用pipeline封装以避免数据泄露和测试集误fit。

直接用 LinearRegression 拟合非线性关系,通常会得到明显弯曲的残差、低 R² 和肉眼可见的欠拟合——这不是模型“不行”,而是你没把非线性结构显式地喂给它。
为什么多项式扩展是多数场景的第一选择
因为它的原理最透明、控制最直接:把原始特征 X 显式转换成 [1, X, X², X³, ..., X^d],再交给线性模型拟合。线性模型本身不“知道”自己在拟合曲线,它只是对这些新特征做加权求和。
- 对一元非线性(如抛物线、S型趋势),
PolynomialFeatures(degree=2)或degree=3往往就能显著提升R² - 对多元输入(如
X1,X2),degree=2会自动加入X1²,X2²,X1*X2等交互项,这是捕捉协同效应的关键 - 注意:不要盲目设高阶(如
degree=5),容易过拟合,尤其样本少时;先从2开始,用cross_val_score验证泛化能力
必须配合标准化,否则 fit_transform 会失效
PolynomialFeatures 输出的特征量纲差异极大(比如原始 X 在 [0, 10],X² 就跑到 [0, 100],X³ 到 [0, 1000])。如果不标准化,LinearRegression 的系数会被高次项主导,训练不稳定,predict 结果抖动大。
- 正确顺序是:
StandardScaler→PolynomialFeatures→LinearRegression(或用Pipeline封装) - 切记:测试集必须用训练集拟合出的
scaler和poly分别调用transform,不能重新fit - 错误示例:
poly.fit_transform(X_test)—— 这会让测试集的多项式基与训练集不一致,预测完全不可信
当多项式不够用时,试试 FunctionTransformer 自定义映射
有些物理/业务关系明确是非线性的,比如衰减(exp(-X))、饱和(1/(1+exp(-X)))、幂律(X**0.5)。硬塞进多项式反而需要很高阶才能逼近,还引入冗余噪声。
- 用
sklearn.preprocessing.FunctionTransformer可以精准注入领域知识:from sklearn.preprocessing import FunctionTransformer import numpy as np <h1>定义已知的非线性变换</h1><p>log_transform = FunctionTransformer(np.log1p, validate=True) # log(1+X),防负值 sqrt_transform = FunctionTransformer(np.sqrt, validate=True)</p><h1>组合使用(需 Pipeline)</h1><p>from sklearn.pipeline import Pipeline pipe = Pipeline([ ('log', log_transform), ('poly', PolynomialFeatures(degree=2)), ('lr', LinearRegression()) ]) </p> - 关键点:
validate=True保证输入是数值型;若含缺失值,得先用SimpleImputer处理,否则np.log1p报RuntimeWarning
交叉验证时最容易漏掉的陷阱
用 cross_val_score 评估多项式回归性能时,如果只传入 X_poly(即已经扩展好的特征矩阵),就等于把数据泄露提前完成了——你在 CV 折外“偷看”了整个特征工程的结构。
- 正确做法:把整个预处理+建模流程封装进
Pipeline,再传给cross_val_score - 反例:
cross_val_score(LinearRegression(), X_poly, y)—— 这个X_poly是用全部训练数据拟合的,CV 失效 - 正例:
cross_val_score(Pipeline([('poly', poly), ('lr', lr)]), X, y),让每折都独立做fit_transform
真正难的不是写对那几行代码,而是在 PolynomialFeatures 的 degree、交互项是否保留、是否添加先验变换之间做取舍——这取决于你对业务机制的理解程度,而不是 CV 分数高低。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











