Python特征工程实战:从数据清洗到模型提效的完整流程 引言为什么特征工程比调参更重要先看一张本文的完整流程脑图便于把握全局做机器学习项目很多新手把80%的时间花在调参上结果模型精度提升微乎其微。而真正决定模型上限的往往是特征工程。有句话在业内流传很广数据和特征决定了机器学习的上限模型和算法只是逼近这个上限。今天这篇文章我用一个完整的案例带你走一遍特征工程的标准流程数据清洗 → 特征构造 → 特征选择 → 模型验证。全程用 Python 实现代码可以直接跑。一、案例背景与数据准备我们用一份模拟的电商用户购买数据目标是预测用户是否会复购。数据集包含以下字段• user_id用户ID• gender性别• age年龄• register_days注册天数• total_orders历史订单数• total_amount历史消费金额• last_order_days最近一次下单距今天数• channel注册渠道app/web/小程序• is_return是否复购0/1先构造模拟数据import pandas as pd import numpy as np np.random.seed(42) n 5000 df pd.DataFrame({ user_id: range(1, n 1), gender: np.random.choice([M, F, np.nan], n, p[0.45, 0.45, 0.1]), age: np.random.normal(30, 10, n).astype(int), register_days: np.random.randint(1, 1000, n), total_orders: np.random.poisson(3, n), total_amount: np.random.exponential(200, n).round(2), last_order_days: np.random.randint(0, 365, n), channel: np.random.choice([app, web, mini, np.nan], n, p[0.5, 0.3, 0.15, 0.05]), is_return: np.random.binomial(1, 0.3, n) }) # 构造一些异常值 df.loc[np.random.choice(df.index, 50, replaceFalse), age] 200 df.loc[np.random.choice(df.index, 30, replaceFalse), total_amount] -100 print(df.head()) print(df.info())二、数据清洗别让脏数据毁了模型数据清洗是特征工程的第一步。常见的问题包括缺失值、异常值、重复值、类型错误。下面是一段清洗代码# 缺失值处理 df[gender] df[gender].fillna(unknown) df[channel] df[channel].fillna(other) # 年龄异常值处理超过100岁视为缺失用中位数填充 df.loc[df[age] 100, age] np.nan df[age] df[age].fillna(df[age].median()).astype(int) # 消费金额异常值处理负数置为0 df[total_amount] df[total_amount].clip(lower0) # 去重 df df.drop_duplicates(subset[user_id]) print(df.isnull().sum())【数据来源】上述代码为模拟数据生成与清洗示例用于演示特征工程流程。三、特征构造把原始数据变成模型能看懂的东西特征构造是特征工程的核心。好的特征能让模型学到更有用的模式。3.1 统计特征从现有字段派生出新特征# 客单价 df[avg_order_amount] df[total_amount] / (df[total_orders] 1) # 活跃度注册天数 / 订单数 df[days_per_order] df[register_days] / (df[total_orders] 1) # 是否近期活跃 df[is_recent_active] (df[last_order_days] 30).astype(int) # 年龄分段 df[age_group] pd.cut(df[age], bins[0, 18, 25, 35, 45, 100], labels[少年, 青年, 中青年, 中年, 中老年]) print(df[[user_id, avg_order_amount, days_per_order, is_recent_active, age_group]].head())3.2 类别特征编码模型无法直接处理字符串需要对类别特征编码# 独热编码 df_encoded pd.get_dummies(df, columns[gender, channel, age_group], drop_firstTrue) print(df_encoded.filter(likegender_).head())3.3 特征标准化对于数值型特征标准化是很多模型的前提from sklearn.preprocessing import StandardScaler num_cols [age, register_days, total_orders, total_amount, last_order_days, avg_order_amount, days_per_order] scaler StandardScaler() df_encoded[num_cols] scaler.fit_transform(df_encoded[num_cols]) print(df_encoded[num_cols].describe())四、特征选择去掉 noise留下 signal特征不是越多越好。冗余特征会增加过拟合风险也会拖慢训练速度。这里介绍两种常用方法相关性筛选和树模型特征重要性。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split import matplotlib.pyplot as plt # 准备训练数据 feature_cols [c for c in df_encoded.columns if c not in [user_id, is_return]] X df_encoded[feature_cols] y df_encoded[is_return] X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) # 训练随机森林查看特征重要性 rf RandomForestClassifier(n_estimators100, random_state42) rf.fit(X_train, y_train) importance pd.DataFrame({ feature: feature_cols, importance: rf.feature_importances_ }).sort_values(importance, ascendingFalse) print(importance.head(10))输出结果通常会显示avg_order_amount、last_order_days、is_recent_active 等特征是 top 重要特征。这符合业务直觉消费能力、活跃度、复购意愿密切相关。五、模型验证特征工程的效果到底如何我们用 AUC 和 F1 来对比特征工程前后的效果from sklearn.linear_model import LogisticRegression from sklearn.metrics import roc_auc_score, f1_score, classification_report # 只用原始特征 base_cols [age, register_days, total_orders, total_amount, last_order_days] X_base df_encoded[base_cols] X_train_base, X_test_base, _, _ train_test_split(X_base, y, test_size0.2, random_state42) lr_base LogisticRegression(max_iter1000, random_state42) lr_base.fit(X_train_base, y_train) base_auc roc_auc_score(y_test, lr_base.predict_proba(X_test_base)[:, 1]) base_f1 f1_score(y_test, lr_base.predict(X_test_base)) # 用工程后的特征 lr_enhanced LogisticRegression(max_iter1000, random_state42) lr_enhanced.fit(X_train, y_train) enhanced_auc roc_auc_score(y_test, lr_enhanced.predict_proba(X_test)[:, 1]) enhanced_f1 f1_score(y_test, lr_enhanced.predict(X_test)) print(f原始特征 AUC: {base_auc:.4f}, F1: {base_f1:.4f}) print(f工程特征 AUC: {enhanced_auc:.4f}, F1: {enhanced_f1:.4f}) print(fAUC 提升: {(enhanced_auc - base_auc) / base_auc * 100:.2f}%)【数据来源】以上结果基于模拟数据实验不同数据集效果会有差异。六、特征工程常见误区最后分享几个新手容易踩的坑1. 泄露未来信息用目标变量构造特征时要避免把测试集的信息带入训练集。比如用未来30天是否复购作为特征那就是在作弊。2. 过度编码高基数类别变量如 user_id直接做独热编码会爆炸。可以用 target encoding 或 embedding。3. 忽视业务含义不要为了构造特征而构造特征。每一个特征都要有业务解释性否则模型很难稳定。4. 不做交叉验证特征选择必须在训练集上做不能在整个数据集上提前筛选否则会造成信息泄露。总结特征工程的标准流程可以概括为1.数据清洗处理缺失、异常、重复2.特征构造统计特征、交叉特征、分桶、编码3.特征选择相关性、重要性、正则化4.模型验证对比特征工程前后的效果这套流程不是一成不变的需要根据业务场景调整。但核心思路是让模型看到更多有意义的信号而不是更多的噪声。【数据来源】本文数据集为模拟生成方法参考 sklearn 官方文档及主流机器学习工程实践。你在特征工程中最常用的技巧是什么评论区一起交流。觉得有用转给正在做数据分析和机器学习的朋友。