首页 / 资讯中心 / 文章详情

手工特征工程与深度网络自动学习:原理、场景与最佳实践

手工特征工程与深度网络自动学习:原理、场景与最佳实践 ★ FEATURED ARTICLE
我最早做传统机器学习项目的时候经常被问一句话你花那么多时间搞特征工程为什么不直接上深度学习后来我开始大量使用深度神经网络deep neural networks又被另一句话追着跑特征工程不是很重要吗怎么到了神经网络这里就全靠网络自己学这两句话的背后恰好是整个数据科学领域对 Feature Engineering 的两种典型态度手工构造特征hand-crafted以及深度网络自动学习特征。做表格数据、图像、文本序列都绕不开这个选择题。这篇笔记我想把这两条路线放在一起掰开聊把各自的原理、适用场景、实操方法和配合方式讲透。如果你正在纠结该把精力放在构造特征还是调网络或者想搞懂神经网络内部到底在学什么这篇应该能给你一个比较完整的坐标系。1. 先弄清问题特征工程究竟是给模型喂饭还是做饭很多人对特征工程的理解停留在造变量这个动作上但我更愿意把它定义为把原始数据翻译成模型更容易学、更符合问题先验的形式。这个翻译过程决定了模型能从数据里“看到”什么也就决定了效果的天花板。1.1 数据和特征决定效果上限算法只是逼近上限业界流传一句话数据和特征决定了机器学习的上限模型和算法只是逼近这个上限。这句话不是鸡汤是大量项目验证过的经验。同样是用户下单预测如果只给模型一个“注册时间”它很难学到有意义的规律但如果我手工构造出“注册到首次购买的间隔”“近30天活跃天数”“午夜时段的操作次数占比”模型在同样的算法下AUC往往能涨一大截。这不是模型变聪明了而是特征把信息放到了模型容易抓住的位置。我用一个生活化类比来解释模型就像一个被蒙住眼睛的厨师特征工程是提前把食材切好、腌好、摆到盘子里模型只需要按顺序下锅炒出来的菜自然好吃。神经网络这条路则是给厨师一副眼睛让他自己看食材、自己决定怎么切但前提是你得有足够多的食材让他练习。1.2 手工特征与深度网络的两条路线差异手工特征工程的本质是先验知识驱动。你把业务经验、领域规律显式地编码成特征交给逻辑回归、GBDT甚至神经网络去学习。它的优点是可控、可解释、小样本下也稳定缺点是费人力、依赖领域经验、很难覆盖所有可能的模式。深度神经网络的特征学习则相反是数据驱动。它把原始数据像素、文本、用户行为序列直接丢进网络通过反向传播自动调整每一层的权重逐层提取从低级到高级的特征。优点是省人力、能够发现人类容易忽略的复杂交互缺点是数据量要求高、可解释性差、训练成本大。这两条路线不是替代关系而是分工关系。理解这一点是后面所有方案选型的前提。2. 手工特征工程的核心操作逐个拆给你看手工特征工程并不是“凭感觉造变量”它有一批经过验证的常规操作每种操作背后都有明确的动机。下面按特征类型拆开讲。2.1 数值型特征变换、裁剪与标准化的分寸数值型特征最常见的三个操作是对数变换、异常值裁剪和标准化。先说对数变换它主要应付长尾分布。像用户累计消费金额、点击次数这类字段往往几个头部用户占用大部分数值量直接用原始值喂给模型会让分裂点或距离计算被极值主导。取log后能把量级从百万级压缩到十级以内分布更接近对称线性模型和神经网络都会更稳。我试过对同一份电商数据做下单金额预测原始金额直接入模时GBDT也能跑但残差集中在高消费人群取对数变换后整体残差更均匀RMSE降了将近十个点。不过要注意对数变换不是万能药。对于树模型单调变换几乎不改变分裂相对顺序所以提升有限真正受益的是线性模型、SVM、神经网络这类对数值尺度敏感的模型。异常值裁剪的逻辑更直接把超过p99的值强制压到p99。有人觉得“裁剪会丢信息”但实际上极端异常值在业务上往往是错误数据或一次性事件保留它对模型是噪声大于信号。裁剪点选的保守一点就行p95到p99之间都可以交叉验证里试一轮就有数。标准化则是神经网络和线性模型的前置条件。把特征缩放到均值0、方差1可以避免某些特征因为数值范围大而主导梯度更新。注意树模型根本不依赖标准化所以不需要给GBDT做z-score。如果训练数据量不大你完全可以把“对数变换只对网络模型做、标准化只对网络模型做、树模型用原始字段”这种差异化成默认流程。2.2 分箱给线性模型注入非线性分箱在传统特征工程里的地位很高尤其是逻辑回归时代。逻辑回归的决策边界天然是线性的面对年龄对购买意愿的影响先升后降这种倒U型关系直接拿年龄的原始数值进去学是学不出来的。但把年龄分成[18-25]、[26-35]、[36-45]、[46-60]等几个桶再对每个桶做独热编码逻辑回归就能学到分段常数的非线性效应。分箱有等宽、等频和基于标签的分箱几种方式。等宽分箱实现简单但遇到偏态分布会出现某些箱子几乎没样本等频分箱让每个箱子的样本量相同但边界值可能落在同一个数值上造成同一个值被拆进不同箱子有标签时还可以用决策树分箱或卡方分箱让分箱边界和标签分布对齐效果通常更好。我常用的判断标准是如果模型是树模型基本不用刻意分箱树自己就能找到分裂点如果是逻辑回归或者要强解释性的场景分箱是标配。分箱数一般在5到15之间太多会让每个箱子的统计意义变弱太少又丢精度用交叉验证选一次就行。2.3 类别特征编码从One-Hot到统计编码再到Embedding类别特征是表格数据里最麻烦的一类。基数低的时候One-Hot简单直接但高基数类别比如用户ID、商品IDOne-Hot会直接导致维度爆炸和稀疏矩阵大多数模型在这种输入下学不到有效信息。于是有了统计编码。频率编码用类别的出现次数替代类别本身比如“商品被购买过多少次”树模型能从频次里学到“热门商品更可能被再次购买”一类的规律。Target Encoding用类别对应目标均值做编码效果通常不错但很容易跑出数据泄漏必须用out-of-fold方式在当前折内统计标签均值否则验证集得分虚高到没有参考价值。这里有个值得注意的过渡Embedding本质上可以理解为神经网络自动完成的高基数类别编码。你把类别ID映射成一个可学习的高维向量让网络在训练中自己调整向量的方向。这个思路就是深度网络把“类别特征工程”内化的体现——不需要人手动设计相似度规则网络自己学到“哪些商品在行为上更接近”。2.4 交互特征与时间窗口业务直觉的落点交互特征是把两个或多个字段组合成新特征最常见的是比值和乘积。点击率CTR点击/曝光比单独用点击次数和曝光次数更符合业务直觉同时天然消除了量纲差异。另一个例子是金额与件数组合成“客单价”单独看总金额或总件数都有盲区客单价直接刻画消费层级。时间窗口聚合是风控和推荐系统里的家常便饭。对于用户行为序列我会构造“近7天下单笔数”“近30天活跃天数”“距上次点击的间隔”这类特征。核心思路是近期行为比全量历史更有预测力时间衰减越明显窗口就要设得越短。实际操作里可以同时跑3天、7天、30天多个窗口再让模型去选比拍脑袋定一个窗口要稳。做交互特征最大的坑是组合爆炸。三个特征能乘出三个二阶组合十个特征就是四十五个全造出来既耗时又容易过拟合。我试过用基于树的特征组合筛选或者直接用GBDT叶子节点做特征映射让模型自动找有用交互再把筛选出的交互特征显式构造出来。这种方式既保留人工特征的稳定性又不浪费自动化筛选的能力。3. 深度神经网络究竟在自动学习什么特征很多人的误区是深度神经网络似乎凭空“变出”了特征。实际上它并没有摆脱特征工程而是把人的精力从“计算特征数值”转移到了“设计网络结构”。这个视角能让很多问题豁然开朗。3.1 端到端与表示学习从原始特征到抽象特征神经网络的每一层都在做特征变换只是这个变换是自动学出来的。图像识别里浅层卷积学到边缘、线条中层学到纹理、形状深层学到物体部件甚至整体语义。这个过程叫表示学习深度模型把“原始输入-特征-输出”三阶段整合成了端到端的学习。在表格数据里也一样。假设你有年龄、收入、历史购买次数三个字段DNN的第一层可能学到“收入高且购买次数多”这个隐含组合第二层又把这种组合和年龄做二阶交互。如果按传统手工做法这个二阶交互特征需要靠人想到、算出来再喂给模型而DNN在用足够的样本自动逼近它。但自动学习是有代价的。一是需要的数据量大否则学出一堆噪声模式二是不可解释出了问题很难定位到具体是哪个特征在起作用。我在实际项目中见过不少团队在样本量只有两三万的情况下强上深层模型效果反而不如GBDT加几个手工特征原因就在于此。3.2 网络结构本身就是人工先验CNN适合图像不是因为“图像就适合CNN”而是因为CNN结构里内置了局部性和平移等变性两个先验。卷积核只看局部区域不管物体出现在图像左上角还是右下角都能提取到同样的局部模式。这个先验不需要人显式计算而是用网络结构表达出来了。循环神经网络和Transformer同理。RNN假设序列依赖沿时间方向传播注意力机制则假设序列里任意两个位置都可能直接相关。这些先验如果换成手工特征工程的做法对应的是“滑动窗口统计量”“滞后项”“共现矩阵”等操作。只不过深度网络把这些特征放在了结构里由优化算法自动适配。Embedding是所有表格数据深度模型里最典型的手工特征替代物。传统做法里你可能费劲计算类别之间的相似度、共现频率步Embedding把类别映射到向量空间直接让距离近的类别共享相似表示。本质上这就是一个大规模自动化的类别特征工程模块。3.3 上DNN不代表可以不做预处理这是很多人最会误会的点。我见过直接把包含缺失值、异常字符串、不同量纲的原始表丢给PyTorch模型的项目结果模型训练根本收敛不了还反过来怪深度学习“不适合表格数据”。实际上即便深度网络能自动学特征基本的清洗、缺失值填充、缩放、类别编码仍然必要。举一个实际例子对稀疏的类别ID直接做Embedding之前至少要保证只知道出现频次过低的ID能被映射为统一的UNK向量。对数值型特征标准化仍然能明显加速收敛。深度网络确实能“自动学”很多交互关系但对脏数据和坏尺度没有免疫力。用一句话总结自动特征学习替代的是“特征构造”环节不是“数据清洗”环节。4. 落地方案什么时候手工什么时候自动怎么组合方案选型没有绝对答案但有可复用的判断标准。我结合一线项目的经验整理了一套评估维度按表里的思路走绝大多数场景不会选错。判断维度侧重手工特征hand-crafted侧重深度网络自动学习数据规模小样本千级到数万级更稳大数据十万级以上才有优势可解释性强特征含义明确弱几乎没有直接解释性训练成本低CPU也能跑高通常要GPU且调参周期长数据形态表格、强业务逻辑字段图像、文本、序列、高维稀疏先验依赖高度依赖领域专家更依赖数据和网络结构4.1 选型判断标准与场景对照如果你处理的是图像或自然语言不需要犹豫直接上深度网络手工特征只做辅助。图像里旋转、裁剪、颜色增强属于数据层面的预处理不是手工特征。文本里可以用TF-IDF、词频统计作为浅层基线但Transformer类的模型能自动学出更丰富的语义表示。如果你处理的是表格数据且样本量不大手工特征加GBDT几乎是最稳健的起点。很多竞赛里的表格数据冠军方案至今仍然是特征工程加树模型集成不是深度学习。样本量一旦超过十万且特征之间存在复杂交互比如推荐系统中的用户行为序列、广告点击日志深度模型才真正有机会超过树模型。还有一类重要场景是混合模式一方面你手工构造一部分强先验特征另一方面把其他原始数据也喂进网络让网络自己补全剩余模式。这既保留了业务知识的作用又给了数据驱动模型发挥的空间。例如在OCR识别任务里我会额外输入字符宽度、图像对比度、行距这些手工特征给模型在推荐任务里把专家构造的用户活跃度特征和序列Embedding拼接后一起输入DNN。4.2 手工特征与DNN配合的实操流程我的建议是在项目启动时先搭一个相对完整的方案框架不要一上来就纠结“到底用哪条路”。一个实用的标准流程是先做基础清洗和探测性分析再手工构造一批低风险的基础特征然后分别训练一个GBDT基线和一个DNN基线最后选择效果更好的一方或者做融合。下面这段伪代码是从我负责的一个用户复购预测项目里简化出来的可以作为落地模板参考# 1. 基础清洗缺失值、异常值、类型修正 df clean_raw_data(df) # 2. 手工特征块 df[purchase_interval_days] (df[last_purchase_date] - df[first_purchase_date]).dt.days df[active_ratio_last_30d] df[active_days_30d] / max(df[obs_days], 1) df[avg_order_value] df[total_amount] / df[order_cnt].clip(lower1) # 3. 训练/验证集拆分必须放在特征统计之前 train, valid train_test_split(df, test_size0.2, random_state42) # 4. 手工特征同时支持树模型和DNN X_train_tree train[hand_features] X_train_dnn build_nn_input(train, hand_features, embed_cols) # 5. 分别训练后再加权融合 pred 0.5 * gbdt_model.predict(X_train_tree) 0.5 * dnn_model.predict(X_train_dnn)这个方案的好处是树模型作为强基线能快速判断特征工程做得到不到位DNN在特征量足够大时有机会超出基线。融合也不止加权平均一种可以拿树模型的预测概率作为DNN的新增特征或者反向操作让两个模型的优势互补。实际操作时我会先跑一个纯手工特征的GBDT再跑一个纯DNN最后跑融合版三档效果对比清晰复盘时也容易定位问题出在特征还是模型。5. 常见问题与排查技巧实录特征工程里的坑绝大多数不是理论知识不够而是实操细节没处理干净。下面几条都是我实际踩过、也帮别人排查过的坑。5.1 特征泄漏我踩得最重的一个坑第一次我自己做目标编码的时候在整份训练集上计算了类别均值然后把编码后的特征喂给模型。线下验证集的AUC高得惊人我一度以为找到了制胜特征结果线上效果一塌糊涂。后来排查原因才意识到我在划分训练集和验证集之前就已经计算了编码验证集的信息通过类别均值泄漏到了训练过程里等于考试前先看到了答案。正确的做法是确保任何基于标签的统计包括目标编码、分箱边界、标准化参数都只能在训练集内拟合然后应用到验证集。更稳妥的办法是用K折交叉验证做out-of-fold编码让每折都用其他折的统计信息来生成当前折的特征。这个教训后来被我写进了团队的特征工程规范里凡是涉及标签的统计量一律禁止在全量数据上计算。5.2 编码与变换里的隐蔽问题高基数类别直接One-Hot是新手最容易踩的坑。我曾经接过一个商品推荐项目类目ID有二十多万个直接One-Hot之后特征矩阵稀疏得吓人GBDT训练时间暴涨效果还很差。后来改成频率编码加Top-K独热只给出现次数最多的前几百个类目单独建特征其余归入其他类训练时间降了一个数量级效果反而提升了。另一个隐蔽问题是时序数据里的标准化。金融场景的时间序列如果按全样本标准化后半个时间段的数据信息会被前半个时间段“偷走”。正确的做法是只用训练期窗口的均值方差去做标准化线上推理时沿用同一组参数不能跟着新数据滚动更新。这个问题导致的泄漏不显眼但一旦出现回测成绩会失真。5.3 深度模型下的特征陷阱速查表常见问题典型表现解决办法原始ID直接做Embedding低频ID的向量训练不充分效果差低频ID统一映射为UNK或用频次过滤数值特征未标准化DNN收敛慢loss震荡训练前用训练集统计量做z-score高基数类别做One-Hot再进DNN维度爆炸内存溢出换Embedding层或统计编码把树模型特征直接喂给DNN稀疏度过高网络学不动先稠密化或改用DNN适配的特征表示手工特征和原始特征同时堆给DNN特征尺度不一致梯度不稳分组处理后拼接输入这张表里的问题我基本都遇到过。尤其是DNN输入那段手工特征如果已经做过对数变换和分箱数值范围通常比较温和而原始数值特征可能动辄几百万直接拼接会让网络训练早期被大尺度特征主导。解决办法是每种特征单独预处理之后再做拼接或者给不同特征组配置不同的Embedding维度和归一化方式。最后聊一个实际体会折腾了几年特征工程我最大的体会是不要把手工特征和深度网络看成对立面它们在绝大多数项目里是接力关系。手工特征负责把业务先验固化下来深度网络负责在更广阔的假设空间里做补充搜索。哪怕是纯图像项目我也会保留一部分手工统计特征作为辅助信号比如目标尺寸分布、对比度、密集程度这些信息经常能帮网络少走弯路。如果你正处在“该不该做手工特征工程”的纠结里我的建议是先花两天把手边最有业务直觉的特征做出来哪怕只是最简单的比率和时间窗口然后跑一个GBDT基线。这个基线一方面给你一个可信的参考点另一方面能让你对数据的信息量建立体感。之后再决定要不要上DNN或者怎样把两条路线结合起来思路会清晰很多。
阅读完成 · 觉得有帮助?
咨询建站