跳至内容
特征工程与数据预处理

特征工程与数据预处理

「垃圾进,垃圾出」——原始数据质量和特征设计的好坏,对最终效果的影响往往大于算法选择。这篇系统梳理数据预处理和特征工程的核心步骤,配实用代码。

数据预处理

缺失值处理

先搞清楚缺失的原因,再决定策略:

场景推荐策略
随机缺失、缺失量少均值/中位数/众数填充
有规律缺失(如高端用户不填收入)单独作为一个「未知」类别编码
大量缺失(>50%)考虑直接删列
时序数据前向/后向填充或插值
import pandas as pd

df = pd.read_csv("data.csv")

# 数值列:用中位数填充(比均值对异常值更稳健)
df["age"].fillna(df["age"].median(), inplace=True)

# 类别列:填充为出现频率最高的值
df["city"].fillna(df["city"].mode()[0], inplace=True)

# 查看各列缺失率
print(df.isnull().mean().sort_values(ascending=False))

异常值处理

异常值不一定是「噪声」——业务异常(如欺诈)本身就是你要学习的信号,删掉反而有害。

  • 可视化先行:箱形图看分布,散点图找离群点。
  • IQR 法:1.5 倍四分位距之外的点标记为异常。
  • 处理方式:截断(Clipping)通常比直接删除更安全——把极端值压到合理上下界。
# 对 salary 列做上下界截断(保留 1%~99% 分位数范围内)
lower = df["salary"].quantile(0.01)
upper = df["salary"].quantile(0.99)
df["salary"] = df["salary"].clip(lower, upper)

特征编码

机器学习模型只认数字,类别特征必须先编码。

独热编码(One-Hot Encoding)

适合无序类别,如城市、颜色。缺点:高基数列会炸维度。

df = pd.get_dummies(df, columns=["city"], drop_first=True)

标签编码(Label Encoding)

适合有序类别,如评级(低/中/高)、学历。

from sklearn.preprocessing import OrdinalEncoder

enc = OrdinalEncoder(categories=[["初中", "高中", "本科", "研究生"]])
df[["edu"]] = enc.fit_transform(df[["edu"]])

目标编码(Target Encoding)

用目标变量的均值替换类别值,适合高基数类别(如商品 ID)。需结合交叉验证做,否则容易数据泄露。

数值特征缩放

不缩放,基于距离的算法(KNN、SVM)和梯度下降的模型(神经网络、线性回归)会被量级大的特征主导。

方法公式适用场景
标准化 Z-Score(x - mean) / std特征近似正态分布;大多数情况首选
归一化 Min-Max(x - min) / (max - min)需要把值压到 [0, 1];对异常值敏感
鲁棒缩放 Robust(x - median) / IQR有异常值时更稳健
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
# 注意:fit 只在训练集上做,transform 在训练/测试集上分别做
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled  = scaler.transform(X_test)     # 不能 fit_transform!
测试集必须用训练集的统计量来变换(即只 transform,不 fit_transform),否则发生数据泄露,评估失真。

特征选择

特征不是越多越好。冗余特征增加噪声、拖慢训练、降低可解释性。

  • 方差过滤:方差接近 0 的特征几乎不提供信息,直接删。
  • 相关性过滤:两个特征相关系数 > 0.95,留其中一个。
  • 基于模型的重要性:训练一个随机森林,按 feature_importances_ 排序,砍掉末尾。
  • 递归特征消除(RFE):sklearn 提供 RFE 类,自动剔除最不重要的特征。
from sklearn.ensemble import RandomForestClassifier
import numpy as np

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train_scaled, y_train)

# 按重要性排序
importances = pd.Series(model.feature_importances_, index=feature_names)
print(importances.sort_values(ascending=False).head(10))

一句话小结

预处理的顺序:处理缺失值 → 处理异常值 → 编码类别特征 → 缩放数值特征 → 特征选择。每步的 fit 只看训练集,处理逻辑一致地应用到测试集。

最后更新于