PolynomialFeatures是scikit-learn中唯一原生支持自动构造特征交互项(如x1*x2、x1²)的工具,仅做特征变换而不依赖模型训练;默认生成所有组合乘积项并含偏置项,易致共线性,建议设include_bias=False;interaction_only=True可禁用平方项、仅保留纯交互;高维时维度爆炸风险高,需谨慎控制degree与n;不处理缺失值和类别型变量,须前置Imputer与Encoder;列名需手动映射以保障可解释性。

特征交互项生成的核心函数是 PolynomialFeatures
Scikit-learn 里唯一原生支持自动构造特征交互项(如 x1*x2、x1²)的工具就是 PolynomialFeatures,它不依赖模型训练,只做特征变换。别指望 StandardScaler 或 PCA 干这事——它们压根不生成新特征。
关键点:它默认只生成**所有组合的乘积项**,且默认包含偏置项(全 1 列),这在多数下游模型(如 LinearRegression)中会导致冗余甚至共线性问题。
-
degree=2会生成所有一阶项 + 所有两两乘积 + 所有平方项(如x1²,x2²) -
interaction_only=True可禁用平方项,只保留纯交互(如x1*x2,不含x1²) -
include_bias=False强烈建议设为False,尤其当你后续要接带截距的模型时
如何避免维度爆炸和内存溢出
PolynomialFeatures 的输出维度随原始特征数 n 和 degree 急剧增长:对 n=10、degree=3,输出特征数可达 220+;n=20 时直接跳到 1771 —— 这还没算稀疏矩阵开销。
- 先用
n_features_in_查原始维度,再手动估算输出维度:from sklearn.preprocessing import PolynomialFeatures; pf = PolynomialFeatures(degree=2); pf.fit(X); print(pf.n_output_features_) - 对高维输入(比如 >15 列),优先尝试
interaction_only=True, degree=2,它只生成C(n,2)个新特征 - 配合
SparseThreshold或直接用scipy.sparse矩阵输入,能显著减小内存压力
与 Pipeline 配合时的常见陷阱
把 PolynomialFeatures 塞进 Pipeline 很自然,但容易忽略两个硬伤:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 如果上游有缺失值(
np.nan),PolynomialFeatures会直接报错ValueError: Input contains NaN,它不做任何插补 —— 必须在它前面加SimpleImputer - 它不处理类别型变量:传入字符串或
category类型列会触发TypeError: A sparse matrix was passed, but dense data is required—— 务必提前用OneHotEncoder或OrdinalEncoder编码 -
fit_transform和transform行为一致,但注意:一旦fit完,它的列顺序和命名就固定了,后续transform输出必须严格对齐
怎么验证生成的交互项确实按预期工作
别只信文档,动手检查最可靠。拿三列数据 X = [[1, 2, 3]] 测试是最小可验证单元:
from sklearn.preprocessing import PolynomialFeatures X = [[1, 2, 3]] pf = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False) print(pf.fit_transform(X))
输出是 [[1. 2. 3. 2. 3. 6.]],对应 [x1, x2, x3, x1*x2, x1*x3, x2*x3] —— 注意没有 x1² 等平方项(因 interaction_only=True),也没有开头的 1.0(因 include_bias=False)。
实际项目中,列名丢失是个隐形坑:PolynomialFeatures 不提供 get_feature_names_out 以外的列名追溯能力,而该方法返回的是类似 ['x0', 'x1', 'x2', 'x0 x1', 'x0 x2', 'x1 x2'] 的字符串,和原始列名完全脱钩。如果你依赖可解释性,得自己存原始列名并映射。

















