尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

机器学习特征工程全解析:从概念到实战,提升模型效果的关键

机器学习特征工程全解析:从概念到实战,提升模型效果的关键 很多刚开始学机器学习的人会把大量时间花在模型调参上却忽略了真正决定效果上限的一步特征工程。同一个数据集、同一个算法有人跑出 AUC 0.85有人只能得到 0.72差别往往不在模型而在喂给模型的特征。这份内容是 100 天机器学习系列里第 23 天的主题专门把特征工程单独拿出来讲原因是它太容易被跳过了。适合正在入门机器学习、已经能跑通几个基础模型、但总觉得结果不稳定的读者。这篇文章会从概念讲到实操再讲排查和边界尽量让看完的人能直接照着做。先给结论特征工程不是模型的外围杂活而是建模流程里最影响效果、也最需要业务判断的一环。数据和特征决定了效果的上限模型只是在逼近这个上限。1. 特征工程到底是什么为什么它比模型调参更影响结果1.1 特征工程的边界输入和输出是什么特征工程就是把原始数据转换成更适合模型学习的形式。这里的“适合”不是一个抽象说法而是有明确判断标准的模型能不能读取、数据有没有缺失和异常、数值范围是不是相差太大、类别字段有没有合理编码、有没有把时间、文本、组合关系这些信息真正暴露给模型。输入通常是一张原始表输出是另一张表但字段集合和数值分布都变了。举个例子原始表里有一列“注册日期”模型没法直接理解“3 月 15 日”和“7 月 2 日”之间的复杂含义。特征工程把它拆成“注册月份”“注册周几”“距今天数”模型才可能从中学到规律。这个过程的本质是你替模型先做了一轮信息整理。模型自己没有业务背景不会自动知道“距今天数”比“注册日期”更有用。你能给出多少有效信息模型就能学到多少。1.2 特征工程、模型选择和调参优先级怎么排很多入门教程会把流程写成“数据清洗 → 模型训练 → 调参”好像特征工程只是清洗的一个子步骤。实际落地时优先级应该是特征工程优先于模型调参模型选择优先于精细调参。换句话说如果特征没有处理好用多好的调参工具都很难补回来。我见过不少人花了一整天调 XGBoost 的 max_depth 和 learning_rate结果后来发现训练集里有一个 ID 列被当成数值特征送进去产生了严重的数据泄露。先做特征工程再谈模型这个顺序不能反。1.3 判断特征工程做没做到位看三个标准特征是否完整进入模型有没有该处理的列直接以原始形式丢给了算法。特征是否可重复同一套处理逻辑训练集和测试集能一致执行不会因为数据量不同产生偏差。特征是否带来信息增量新特征不是堆数量而是真的能让模型更容易区分目标类别或预测数值。这三个标准看起来简单实际大部分报错和效果波动都是从这里冒出来的。后面第四部分会专门讲排错。2. 四类最常用的特征处理方法什么时候用哪种2.1 缺失值处理删除、填充还是单独标记缺失值是特征工程里最先碰到的问题。处理方法不是固定几种而是要看缺失比例和缺失含义。缺失比例很低比如不到 1%可以直接删除对应行。缺失比例较高但字段本身重要就要考虑填充。数值型特征常用均值、中位数填充有序列关系的时间特征用前向填充更合理。类别型特征可以用众数或者新增一个“缺失”类别。这里有一个容易忽略的点缺失本身可能带有业务信号。比如用户没有填写收入可能说明收入较低或信息敏感这时候与其只做填充不如增加一列“是否缺失”让模型自己去判断这个信号有没有用。注意填充均值前一定要先看分布。如果字段偏态明显均值容易被极端值拉高用中位数更稳。2.2 类别特征编码Label Encoding、One-Hot 和 Target Encoding类别型特征不能直接进大多数模型需要编码。最简单的 Label Encoding 适合有序类别比如“低、中、高”可以映射成 1、2、3。没有顺序关系的城市名、产品名用 Label Encoding 会强行制造出大小关系多数情况下不推荐。这种时候用 One-Hot Encoding把每个取值变成一列 0/1。One-Hot 的缺点是类别太多时会造成维度爆炸。一个“城市”字段有 300 个取值One-Hot 之后就是 300 列。此时可以考虑 Target Encoding用目标变量的均值去编码类别。比如用户所在城市的点击率作为该城市的特征值。但 Target Encoding 容易过拟合必须配合交叉验证和噪声处理否则验证集效果好、线上效果差。我的做法是有序类别用 Label Encoding无序且取值少用 One-Hot无序且取值多先用业务规则粗分组再考虑 Target Encoding。不要一开始就上复杂编码。2.3 尺度处理标准化、归一化和鲁棒缩放树模型对特征尺度不敏感但线性模型、SVM、KNN 和神经网络都对尺度敏感。如果某个特征取值范围是 0 到 1另一个是 0 到 100000距离计算和梯度更新都会被大数值特征主导。标准化StandardScaler把特征变成均值 0、方差 1适合大多数连续特征。归一化MinMaxScaler把数据压到 [0, 1]适合有明确上下界的数据。RobustScaler 用中位数和四分位数处理对异常值更不敏感。实际选择时我会先看数据有没有较多离群点。有离群点就用 RobustScaler没有就优先 StandardScaler。还要记住缩放器只能在训练集上拟合然后用同一套参数转换验证集和测试集不能直接对整个数据集 fit。2.4 特征构造从日期、文本、组合里挖信息这一部分最需要动脑也最容易体现经验和业务理解。日期字段可以拆出年、月、日、周几、是否节假日、距现在多少天。文本字段可以做长度、关键词命中、情感倾向。两个数值字段可以构造交互特征比如“价格 × 数量”、“身高 / 体重”。连续字段可以分箱把年龄切成“青少年、青年、中年、老年”有时候比原始数值更能帮助模型。构造特征的思路是想想真人做判断时会看什么。预测一个用户会不会续费可能会看注册时长、最近登录时间、历史购买次数这些经常需要从原始时间戳和明细表里汇总出来。特征工程不是凭空造变量而是把业务判断翻译成表格里的列。3. 用一份小数据走一遍完整特征工程流程3.1 示例数据和环境准备下面用一份模拟的“用户是否续费”数据来演示。字段包括用户ID、注册日期、最后登录日期、使用次数、平均使用时长、会员等级、来源渠道、是否续费。环境不需要太复杂Python 环境里装好 pandas、numpy、scikit-learn 就够了。如果你正在搭机器学习环境建议先确认这几个包能正常导入版本不一致时优先升级 scikit-learn。import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline print(pandas, pd.__version__) print(numpy, np.__version__)3.2 第一步先摸清数据结构和缺失情况拿到数据不要急着训练。先看数据 shape、每列类型、缺失率、类别取值数量。df pd.read_csv(user_renewal.csv) print(df.shape) print(df.info()) print(df.isnull().mean().sort_values(ascendingFalse))这一步解决两个问题哪些字段是数值型哪些是类别型哪些字段缺失率过高可能直接删除。比如“来源渠道”一列有 500 个不同取值如果样本只有 2000 条One-Hot 会让矩阵非常稀疏。这时候需要先做业务分组把 500 个渠道按主流渠道和“其他”合并。3.3 第二步数值型和类别型分开处理先定义特征列。用户ID 要删掉它只是唯一标识不携带预测信息。df df.drop(columns[用户ID]) target 是否续费 X df.drop(columns[target]) y df[target] num_features [使用次数, 平均使用时长, 注册到现在的天数] cat_features [会员等级, 来源渠道, 注册月份]数值型特征做两步填充中位数再标准化。类别型特征做两步填充众数再 One-Hot 编码。用 ColumnTransformer 可以把这两套逻辑打包在一起避免手写多次转换导致训练集和测试集不一致。num_transformer Pipeline(steps[ (imputer, SimpleImputer(strategymedian)), (scaler, StandardScaler()) ]) cat_transformer Pipeline(steps[ (imputer, SimpleImputer(strategymost_frequent)), (onehot, OneHotEncoder(handle_unknownignore)) ]) preprocessor ColumnTransformer(transformers[ (num, num_transformer, num_features), (cat, cat_transformer, cat_features) ])3.4 第三步构造几个带业务语义的新特征原始表里只有注册日期和最后登录日期模型没法直接用。我一般会先算两个派生特征注册到现在的天数、最后登录距离今天数。后者尤其重要因为活跃度往往比注册时长更能预测续费。today pd.Timestamp(2025-01-01) df[注册到现在的天数] (today - pd.to_datetime(df[注册日期])).dt.days df[最后登录距今天数] (today - pd.to_datetime(df[最后登录日期])).dt.days df[注册月份] pd.to_datetime(df[注册日期]).dt.month这里要注意边界原始材料里并没有说明数据的具体日期范围示例里的 today 需要根据你的真实数据集调整。实际做的时候最好按数据的最大日期动态计算不要写死。3.5 第四步相关性分析与特征选择特征构造完以后先做一个简单筛查。数值型特征之间如果相关性过高比如 0.95 以上说明信息冗余可以考虑删除一个。特征与目标的相关性是一个参考但不是唯一标准因为特征之间还可能存在交互作用。numeric_cols df.select_dtypes(includenp.number).columns print(df[numeric_cols].corr())快速判断结束后我会用简单模型配合交叉验证做一轮特征选择。比如用随机森林的特征重要性或者用 Lasso 看系数。重点不是选到最少特征而是删掉明显无关的列比如重复的 ID、缺失率超过 80% 且无业务含义的列。3.6 第五步把所有处理逻辑写成一个 Pipeline最重要的一点特征工程不能只在 notebook 里手写要把全流程封装成 Pipeline。这样训练集、验证集、测试集、上线预测走的都是同一套逻辑不会出现训练时用了 A 处理、预测时用了 B 处理的低级错误。from sklearn.ensemble import RandomForestClassifier model Pipeline(steps[ (preprocessor, preprocessor), (classifier, RandomForestClassifier(n_estimators200, random_state42)) ]) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model.fit(X_train, y_train) print(train_acc:, model.score(X_train, y_train)) print(test_acc:, model.score(X_test, y_test))如果训练集准确率远高于测试集说明过拟合。这时候不要只想到调参先检查特征工程里有没有以下问题目标编码直接用全量数据计算、使用了未来信息、删除缺失值前没看测试集分布。4. 特征工程最容易翻车的几个点以及排错顺序4.1 常见错误一数据泄露数据泄露是特征工程里最隐蔽的问题。常见形式有用全量数据的均值和标准差去填充缺失值再切训练测试集导致测试集信息混入训练。目标编码时直接用全样本目标均值没做交叉验证。数据处理包含未来信息比如用“用户是否已经续费”去反推注册时间窗口。判断方法很简单如果你的训练效果极好、测试效果明显下降优先怀疑数据泄露。4.2 常见错误二训练集和测试集处理不一致很多人单独处理 DataFrame训练集手动填充一个均值到了测试集又重新计算均值两次结果不同。甚至有人把测试集也做了删除缺失值导致行数变化预测结果无法对齐。解决方式就是第三节说的 Pipeline 方法。让 preprocessor 只在训练集上 fit再用同一个对象 transform 测试集。4.3 常见错误三盲目增加特征数量特征不是越多越好。每增加一个特征就要增加样本量来支撑否则模型容易学到噪声。有些平台练习任务比如头歌机器学习里的决策树、SVM、K-Means、GBDT 拆解任务看起来是算法差异但很多题目实际卡在特征没有预处理干净。判断特征数量是否合理的经验值样本量是特征数量的 10 倍以上相对安全。如果特征数量已经超过样本量的十分之一优先做特征选择而不是继续构造新特征。4.4 排错顺序先看数据再看代码最后改参数遇到特征工程相关问题不要直接改模型参数按这个顺序排查看数据 shape行数、列数是否和预期一致训练测试切分后有没有对齐。看缺失率每个字段缺失率有没有超过 50%填充策略有没有意外改变分布。看特征分布新特征里有没有大量 0、大量重复值、明显离群点。看预处理逻辑训练和测试是否走同一个 Pipeline缩放器是否用测试集重新 fit。看模型反馈特征重要性集中还是分散有没有一两个特征占比过高。这个顺序能解决大部分“为什么我调了参数还是效果差”的问题。很多时候问题根本不是模型能力而是特征输入本身就不干净。4.5 怎么判断特征工程做得好不好最简单的方法是做对比实验用原始特征直接建模再用处理后的特征建模比较验证集效果。如果提升不明显说明原始特征已经很干净或者新特征没有带来增量信息。如果提升明显恭喜你特征工程真正起作用了。另一个判断维度是稳定性。同一个特征工程流程跑多次结果方差应该很小。如果每次结果波动很大说明某些处理步骤依赖随机性或者全量数据信息需要重新检查。我个人的习惯是每个数据集至少跑三组实验原始特征 默认参数处理后特征 默认参数处理后特征 调参对比这三组结果能清楚看到特征工程的贡献到底有多大。这也是给别人解释“为什么这个模型效果好”时最有说服力的证据。特征工程这件事做的时间越长越会觉得它才是机器学习的核心。模型算法可以查到很多成熟方案但特征处理必须结合数据背景和业务理解。刚开始入门时不用追求构造多复杂的特征先把缺失值、编码、缩放、分离训练测试这些基本功写稳效果就会比很多人强。后面再逐步加入目标编码、交互特征、自动化特征工具慢慢就会形成自己的一套流程。
返回列表