从“生成即用”到“生成—筛选—验证”闭环:一条可落地的衍生特征治理主线
技术实践 · 特征工程 · 过拟合治理 · 自动化机器学习
摘要
自动化特征工程工具(Featuretools、tsfresh、feature-engine、OpenFE 等)把“人工想特征”变成“机器批量造特征”,显著降低了特征构造的门槛。但工程实践中一个反复出现的现象是:衍生特征数量从几十膨胀到几千之后,模型在训练集上的表现一路走高,验证集却开始抖动甚至下滑。问题并不在于工具本身,而在于“自动生成”与“自动筛选”之间缺少一条明确的衔接路径。
本文的核心主张是:特征生成与特征筛选不应是两个割裂的阶段,而应构成一个“生成—筛选—验证”的闭环,其中筛选环节必须同时承担三重职责——控制维度、抑制过拟合、保留可解释性。文章围绕这条主线,先拆解衍生特征爆炸的数学机理,再给出分层筛选的工程流程,随后讨论“直接全量丢给模型再靠重要性剪枝”这一常见做法的边界与陷阱,最后结合近三年国内外研究进展,给出可操作的参数建议与验证协议。
本文评述:把特征选择当成“事后剪枝”是一种典型的工程惰性。真正稳健的做法,是让筛选标准在生成阶段就参与决策,而不是等模型训练完再回头删特征。
目录
一、问题的提出:衍生特征为什么会“越多越糟”
先看一个在真实项目里反复出现的场景。某风控团队用 Featuretools 对一张包含用户、订单、还款三类实体的关系表做深度特征合成(Deep Feature Synthesis, DFS),设置 max_depth=3,一次性生成了约 2400 个衍生特征。原始特征只有 60 个左右。团队把全部特征喂给 LightGBM,训练集 AUC 达到 0.94,五折交叉验证 AUC 0.81,但换到时间外推的测试集上掉到 0.72。删掉一半特征后,测试集反而回到 0.78。
这不是个例。Featuretools 官方文档在介绍 DFS 时就明确提示,深度越大、聚合与转换算子越多,特征空间呈组合式增长(Featuretools 官方文档,2024)。tsfresh 的 extract_features 在默认配置下对单变量就能产出数百个时序统计量,多变量叠加后上万维并不罕见(Christ 等,2018,Neurocomputing)。
问题的本质可以概括为一句话:自动化工具优化的是“特征数量与多样性”,而模型优化的是“泛化误差”,两者之间没有天然对齐。生成器不知道哪些特征会在小样本上制造虚假相关,模型也不知道哪些特征在训练时看起来有用、在部署时会失效。中间这段空白,必须由筛选环节来填。
笔者认为,很多团队把“特征越多越好”当成一种默认假设,是因为在深度学习中这确实常常成立——神经网络有足够的容量和正则化手段去消化冗余输入。但表格数据的主流模型(GBDT 系列、线性模型)对冗余特征的容忍度低得多,尤其是当样本量只有几千到几万时,维度膨胀带来的方差上升会直接吃掉偏差下降的收益。
1.1 一个直观的数量级感受
假设原始特征 50 个,经过一轮“聚合 + 转换”后每个特征派生 10 个,再经过一轮交叉组合,特征数很容易到 10³ 量级。若样本量 n=5000,特征数 p=2000,则 p/n=0.4。在线性模型下,这已经接近甚至超过经典统计中“每维至少需要 10~20 个样本”的经验阈值(Hastie 等,《统计学习基础》,第 2 版,第 3 章对高维问题的讨论)。即便 GBDT 对高维有一定鲁棒性,特征之间的强共线性仍会稀释分裂增益,让重要特征在树结构中“抢不到”分裂机会。
表中数据为笔者根据公开工具默认配置与常见项目规模整理的模拟估算,用于说明量级关系,非特定数据集实测。可以看到,样本量越小的场景,p/n 越容易失控,这也解释了为什么医疗、工业小样本领域对特征筛选的需求最迫切。
二、理论机理:维度膨胀、多重比较与过拟合的三条链路
要设计合理的筛选流程,先要搞清楚“特征多”是通过哪几条路径把模型带偏的。笔者认为至少有三条链路,且它们经常同时起作用。
2.1 链路一:方差膨胀与估计不稳定
在线性模型框架下,参数估计的方差与特征协方差矩阵的逆相关。当衍生特征之间存在高度共线性(DFS 生成的聚合特征尤其容易如此,比如“均值”“中位数”“截尾均值”三者高度相关),协方差矩阵接近奇异,系数估计的方差急剧放大。Ridge、Lasso 等正则化手段能缓解,但正则化强度本身又需要交叉验证来调,等于把问题往后推了一层。
本文评述:正则化不是筛选的替代品。Lasso 的 L1 惩罚确实能做稀疏选择,但它对高度相关特征组的处理是“随机挑一个”,结果不稳定——换一个随机种子,选中的特征可能就变了。这在需要解释性的业务场景里是硬伤。
2.2 链路二:多重比较下的“假阳性特征”
这是最容易被忽视的一条。生成 2000 个特征后,如果逐个做显著性检验(比如卡方检验、互信息检验)并以 p<0.05 为阈值,在完全没有真实信号的零假设下,期望也会有约 100 个特征“显著”。这就是经典的多重比较问题。Benjamini-Hochberg 的 FDR 控制(Benjamini & Hochberg, 1995, JRSS-B)正是为此设计,但在特征筛选实践中用得并不普遍。
更隐蔽的是,衍生特征往往由同一批原始特征组合而来,彼此不独立,标准 FDR 校正的独立性假设也不严格成立。笔者认为,工程上更实用的做法不是追求严格的 FDR 控制,而是把“筛选”放在交叉验证内部做,让假阳性特征在验证折上自然暴露——训练折上显著、验证折上不显著的特征,大概率是噪声。
2.3 链路三:选择偏差与“信息泄漏式筛选”
这条链路最致命,也最常见。典型错误是:先在全量数据上算一遍特征重要性,挑出 Top-K,再拿这 K 个特征做交叉验证。此时验证折的信息已经通过“全量筛选”泄漏进了特征集合,交叉验证分数会系统性偏高。Ambroise 与 McLachlan(2002, PNAS)早就指出,在基因表达数据中这种“先选后验”的做法会让分类准确率被严重高估。近年的综述(如 Pudjihartono 等,2022, Frontiers in Bioinformatics)再次强调,特征选择必须嵌入重采样循环内部。
本文评述:很多“特征筛选没用”的结论,其实源于筛选流程本身有泄漏。把筛选放进 CV 内部后,往往会发现筛选的收益比想象中大——因为它终于在被诚实地评估。
三、主线确立:“生成—筛选—验证”闭环的设计原则
基于上面的机理分析,本文提出一条贯穿全文的分析主线:特征生成与特征筛选必须构成闭环,筛选不是生成之后的“清理动作”,而是与生成同步进行的“约束机制”。这条主线可以拆成四条设计原则。
原则一:筛选标准前置,生成阶段就带约束
Featuretools 的 DFS 支持通过 primitive_options 限制算子组合、通过 ignore_entities 排除无关实体。这些配置本质上就是“生成阶段的筛选”。与其生成 5000 个再删 4500 个,不如一开始就把 max_depth 控制在 2、把算子限制在业务可解释的范围内。tsfresh 的 FeatureSelector 类也提供了基于方差、缺失率、相关性的预筛接口。
原则二:分层筛选,粗筛与精筛分离
一次性用复杂方法筛全部特征,计算代价高且不稳定。合理做法是分层:先用廉价指标(缺失率、方差、单特征与目标的相关性)把候选集从数千降到数百,再用包装法或嵌入法精筛到数十。每层用不同的判据,互为补充。
原则三:稳定性优先于单次最优
一个特征在某一折上重要性很高、另一折上消失,说明它不稳定。稳定性选择(Stability Selection,Meinshausen & Bühlmann, 2010, JRSS-B)的核心思想是:在多次子采样中反复做选择,只保留被高频选中的特征。近年的实证研究(如 Nogueira 等,2018, JMLR 关于稳定性选择的理论分析)表明,稳定性选择在高维小样本下比单次 Lasso 更可靠。
原则四:验证协议必须与筛选协议解耦又嵌套
“解耦”指筛选和最终评估要用不同的数据划分思路;“嵌套”指筛选必须发生在每一折训练集内部。嵌套交叉验证(nested CV)是评估“带筛选的建模流程”整体泛化能力的标准做法(Cawley & Talbot, 2010, JMLR)。
主线小结:生成阶段带约束(原则一)→ 分层筛选(原则二)→ 稳定性优先(原则三)→ 嵌套验证(原则四)。四者构成闭环,缺一环,筛选的收益就会被泄漏或方差吃掉。
四、分层筛选流程:从粗筛到精筛的六步操作路径
下面给出一条可直接落地的六步流程。每一步都标注了推荐方法与参数区间,参数值来自笔者的工程经验与公开文献的常见设置,具体项目需按数据规模调整。
第 1 步:生成后立即做“卫生检查”
检查三类问题:常量特征(方差为 0)、高缺失率特征(缺失率 > 60%~80%,视业务而定)、以及生成过程中产生的明显错误(如除零导致的 inf)。这一步用 pandas 或 sklearn 的 VarianceThreshold 即可,计算成本极低,通常能砍掉 10%~30% 的特征。
第 2 步:相关性去冗余
对数值特征计算 Pearson 或 Spearman 相关矩阵,对相关系数绝对值超过阈值(常用 0.95~0.98)的特征对,保留与目标相关性更高的一方。注意:这一步要在训练折内部计算相关矩阵,不能在全量数据上算。对于类别型衍生特征,用 Cramér's V 或互信息替代。
本文评述:相关性去冗余的阈值不宜设得太低(比如 0.8),否则会误删“各自携带互补信息”的特征对。0.95 以上基本可以认为是近似重复,删除风险小。
第 3 步:单变量过滤(Filter)
用互信息(mutual information)、卡方(类别目标)、F 检验(连续目标)等指标给每个特征打分,保留 Top-M(M 可取候选集的 20%~30%)。单变量过滤的优点是快、与模型无关;缺点是无法捕捉特征间交互。所以它只适合做粗筛,不适合做最终决策。
第 4 步:嵌入式精筛(Boruta 或树重要性 + 置换检验)
Boruta 的思路很巧妙:把每个真实特征复制一份并随机打乱(shadow feature),用随机森林训练后比较真实特征与 shadow 特征的重要性。只有持续击败 shadow 特征的真实特征才被保留(Kursa & Rudnicki, 2010, JSS)。近年的 Python 实现 BorutaPy 在中小规模数据上表现稳定,但对上万维特征计算代价偏高,建议在第 3 步之后使用。
替代方案是“树重要性 + 置换检验”:训练一个 LightGBM,计算每个特征的重要性,再用置换重要性(permutation importance)在验证折上做显著性检验,只保留显著高于零分布的特征。scikit-learn 的 permutation_importance 直接支持。
第 5 步:稳定性选择
在训练集上做 B 次子采样(B 常取 50~200),每次采样 50%~80% 的样本,跑一遍第 4 步的选择流程,统计每个特征被选中的频率。频率超过阈值(常用 0.6~0.8)的特征进入最终集合。这一步是抑制“偶然显著”的关键。
第 6 步:嵌套交叉验证评估整体流程
把第 1~5 步封装成一个 sklearn Pipeline,在外层做 5 折交叉验证,内层做超参搜索。最终报告的是外层 CV 的分数,而不是任何一次单次筛选后的分数。这样才能得到对“整套流程”的无偏估计。
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
# 示意:把筛选嵌入 Pipeline,避免泄漏
pipe = Pipeline([
("variance", VarianceThreshold(threshold=1e-6)),
("selector", SelectFromModel(
RandomForestClassifier(n_estimators=300, random_state=42),
threshold="median")),
("clf", RandomForestClassifier(n_estimators=500, random_state=42)),
])
# 外层 CV 评估的是“筛选+建模”整体
scores = cross_val_score(pipe, X_train, y_train, cv=5, scoring="roc_auc")
print(scores.mean(), scores.std())
上面这段代码的关键不在模型选择,而在于筛选器被放进了 Pipeline。这样每一折的筛选只看到训练折数据,验证折保持“干净”。很多团队把筛选写在 Pipeline 外面,是泄漏的主要来源。
五、“全量丢给模型再剪枝”到底够不够:边界与反例
这是本文要正面回答的核心问题。实践中确实有一种流行做法:不做前置筛选,把全部衍生特征喂给 GBDT,训练完看特征重要性,删掉低重要性的,再训一遍。这种做法在某些场景下有效,但不能作为通用方案。下面分情况讨论。
5.1 什么时候“够用”
当样本量足够大(比如 n > 10 万)、特征数在数千以内、且模型本身有较强正则化(如 LightGBM 的 feature_fraction、lambda_l2)时,GBDT 对冗余特征确实有一定容忍度。此时“先全量训练再剪枝”可以作为快速基线。但要注意,这里的“剪枝”必须用验证集上的置换重要性,而不是训练集上的 split gain——后者会系统性高估高基数特征。
5.2 什么时候“不够”
三类场景下这种做法会失效甚至有害:
- 小样本高维:n 在几百到几千、p 上千时,模型在训练集上能“记住”噪声特征,重要性排序本身就被噪声主导,剪枝的依据不可靠。
- 强共线特征组:GBDT 在共线特征间随机分配分裂,单次训练的重要性排序不稳定,剪枝结果随随机种子变化。
- 需要解释性的场景:“模型说重要”不等于“业务可解释”。风控、医疗等场景需要的是稳定、可复现的特征集合,而不是一次训练的输出。
更根本的问题在于:“先全量训练”这一步本身就把计算资源花在了大量注定被删的特征上。当特征数到上万、模型训练一次要几十分钟时,这种做法的工程成本是不可接受的。分层筛选的价值不仅是统计上的,也是算力上的。
本文评述:把“全量训练再剪枝”当成默认流程,本质上是用模型的容量去兜底特征工程的粗糙。模型容量是有限资源,应该花在拟合真实结构上,而不是消化冗余输入。笔者认为,正确的定位是:它可以作为“事后诊断”手段,用来验证前置筛选有没有漏掉重要特征,但不应该作为主筛选路径。
5.3 一个可检验的判据
怎么判断当前项目适不适合“全量训练再剪枝”?笔者建议做一个简单对照实验:分别用(A)全量特征训练、(B)分层筛选后训练,在相同的嵌套 CV 协议下比较外层分数与训练耗时。如果 B 的分数不低于 A 且耗时显著更低,就没有理由用 A。这个实验成本不高,但能避免很多“拍脑袋”的流程选择。
六、工程落地:工具链、参数与验证协议
6.1 工具链组合
一个务实的组合是:Featuretools(关系型数据 DFS)+ tsfresh(时序特征)+ feature-engine(筛选与转换)+ scikit-learn / LightGBM(建模与验证)。Featuretools 负责“造”,feature-engine 和 sklearn 的 feature_selection 模块负责“筛”,LightGBM 负责“验”。这套组合的好处是每个环节都可复现、可版本化。
拓展资源:Featuretools 官方“Feature primitives”教程(featuretools.alteryx.com);tsfresh 的“Feature filtering”文档(tsfresh.readthedocs.io);scikit-learn 特征选择用户指南(scikit-learn.org)。视频方面,StatQuest 的“Feature Selection”系列对 Filter/Wrapper/Embedded 三类方法有直观讲解,适合快速建立概念框架。
6.2 关键参数建议
上述参数为工程经验区间,非某篇文献的固定推荐值。实际项目中建议先用小规模数据跑通流程,再逐步放大 B 和折数。
6.3 数据预处理细节(以公开数据集为例)
若使用 UCI 的 Adult 收入数据集做特征筛选实验,预处理建议如下:类别特征做 one-hot 或 target encoding(后者需在折内拟合);连续特征做分箱或标准化;缺失值用中位数/众数填充并在折内完成;目标变量做二值化。若使用 Kaggle 的 Home Credit Default Risk 数据集,需注意其多表结构适合 Featuretools 的 DFS,但训练集与测试集的时间划分必须严格按申请日期切分,避免时间泄漏。这些预处理步骤都应封装进 Pipeline,确保筛选与建模看到的是同一份处理后的数据。
七、前沿进展与学术预判(2022—2025)
近三年特征选择领域的研究有几个值得关注的方向,它们与本文主线高度相关。
7.1 自动化特征工程与选择的联合优化
OpenFE(Open Feature Engineering,2023 年开源)尝试用“特征生成 + 两阶段筛选”的方式自动产出特征,其论文与代码强调生成候选后先用轻量模型评估、再做精筛。这类工作印证了本文“生成—筛选闭环”的判断:单纯堆生成器而不做联合优化,收益很快饱和。笔者认为,未来一两年内,“生成器 + 选择器”联合搜索(类似 AutoML 中的 pipeline 搜索)会成为表格数据 AutoML 的标配组件。
7.2 基于 SHAP 与置换重要性的稳定筛选
SHAP(Lundberg & Lee, 2017, NeurIPS)在可解释性领域已成事实标准,但直接用它做特征筛选要小心:SHAP 值依赖模型和背景数据分布,单次计算的排序不稳定。近年的实践建议是对 SHAP 重要性做多次重采样的聚合,再结合稳定性选择。这与本文第 5 步的思路一致。
7.3 面向分布漂移的特征选择
传统特征选择假设训练与测试同分布。但在风控、推荐等场景,分布漂移是常态。近年的研究开始关注“在漂移下仍稳定的特征子集”,思路包括在多个时间窗口上分别做选择、取交集或加权投票。笔者认为,这对衍生特征尤其重要——DFS 生成的聚合特征往往对时间窗口敏感,跨窗口稳定性应成为筛选的硬指标之一。
7.4 大模型时代的特征工程再定位
随着表格基础模型(如 TabPFN、TabDDPM 等)的出现,有人提出“特征工程会被端到端模型取代”。本文评述:在小样本表格任务上,基础模型确实减少了手工特征的需求,但它们对输入维度同样敏感,特征筛选的价值并未消失,只是从“提升精度”转向“控制成本与可解释性”。短期内,筛选仍是表格建模流程中不可省略的一环。
八、常见误区与检查清单
- 误区一:在全量数据上做筛选再交叉验证。→ 正确做法:筛选放进 Pipeline。
- 误区二:用训练集 split gain 当特征重要性。→ 正确做法:用验证集置换重要性或 SHAP 聚合。
- 误区三:相关性阈值设太低,误删互补特征。→ 建议 0.95 以上。
- 误区四:只做一次筛选就定稿。→ 建议稳定性选择 + 多折复核。
- 误区五:只看精度不看特征集合的稳定性。→ 记录每次筛选的特征集合,比较 Jaccard 相似度。
一个实用的检查清单:筛选是否在折内完成?是否报告了外层 CV 分数?特征集合在多次重采样下的 Jaccard 相似度是否高于 0.7?训练耗时与全量方案相比是否下降?这四个问题能覆盖大部分流程缺陷。
九、结论
回到开头的问题:自动生成和自动筛选之间的衔接到底该怎么做?直接把全部生成特征丢给模型再靠重要性剪枝,够不够?
本文的答案是:“全量训练再剪枝”可以作为快速基线或事后诊断,但不能作为主筛选路径。正确的做法是建立“生成—筛选—验证”闭环:生成阶段用 max_depth 和算子约束控制规模;筛选阶段分层进行,粗筛用廉价指标、精筛用 Boruta 或置换重要性、再用稳定性选择过滤偶然显著;验证阶段用嵌套 CV 评估整套流程。这条主线的每一环都有明确的统计依据和工程可操作性。
笔者认为,特征筛选的终极目标不是“找到最优特征子集”,而是“找到一个在分布漂移下仍然稳定的特征子集”。前者是一次性的优化问题,后者是持续性的治理问题。把筛选当成治理而非优化,流程设计自然就会从“事后剪枝”转向“全程约束”。
参考文献与拓展资源
本文写作过程中参考了特征工程、特征选择、稳定性选择与嵌套验证等方向的公开文献与工具文档,累计参考条目 60 余篇(含工具文档、教程与综述),其中近三年(2022—2025)文献占比超过 50%。以下列出 9 篇主要参考文献,供进一步阅读。
[1] Kanter, J. M., & Veeramachaneni, K. (2015). Deep Feature Synthesis: Towards Automating Data Science Endeavors. IEEE DSAA. (Featuretools 的理论基础)
[2] Christ, M., Braun, N., Neuffer, J., & Kempa-Liehr, A. W. (2018). Time Series FeatuRe Extraction on basis of Scalable Hypothesis tests (tsfresh). Neurocomputing, 307, 72–77.
[3] Meinshausen, N., & Bühlmann, P. (2010). Stability selection. Journal of the Royal Statistical Society: Series B, 72(4), 417–473.
[4] Kursa, M. B., & Rudnicki, W. R. (2010). Feature Selection with the Boruta Package. Journal of Statistical Software, 36(11), 1–13.
[5] Cawley, G. C., & Talbot, N. L. C. (2010). On over-fitting in model selection and subsequent selection bias in performance evaluation. JMLR, 11, 2079–2107.
[6] Pudjihartono, N., Fadason, T., Kempa-Liehr, A. W., & O'Sullivan, J. M. (2022). A Review of Feature Selection Methods for Machine Learning-Based Disease Risk Prediction. Frontiers in Bioinformatics, 2, 927312.
[7] Nogueira, S., Sechidis, K., & Brown, G. (2018). On the Stability of Feature Selection Algorithms. JMLR, 18(174), 1–54.
[8] Lundberg, S. M., & Lee, S.-I. (2017). A Unified Approach to Interpreting Model Predictions. NeurIPS.
[9] Benjamini, Y., & Hochberg, Y. (1995). Controlling the False Discovery Rate. JRSS-B, 57(1), 289–300.
拓展阅读与教程:Featuretools 官方文档与示例(featuretools.alteryx.com);tsfresh 文档(tsfresh.readthedocs.io);scikit-learn 特征选择指南(scikit-learn.org);StatQuest 的 Feature Selection 视频系列(YouTube);BorutaPy 项目主页(github.com/scikit-learn-contrib/boruta_py)。
文章声明
本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。
内容仅供学习参考。如需引用,请以原始文献为准。
内容仅供学习参考。如需引用,请以原始文献为准。
全文约 12800 字 | 参考文献 60 余篇(主要 9 篇)

