数据预处理基础:清洗、缺失值、缩放与编码

大家好,我是你们的老朋友。今天咱们聊聊数据预处理。

说实话,我见过太多人一上来就调模型,结果跑出来的结果惨不忍睹。为什么?因为数据没洗干净。你想想看,垃圾数据进去,出来的只能是垃圾结果。这可不是我吓唬你,我在项目里踩过的坑,今天全部分享给你。

核心观点:数据预处理占整个机器学习项目 60% 以上的工作量。别嫌烦,这一步做不好,后面全是白搭。

一、数据清洗——先把脏东西筛掉

数据清洗,说白了就是去掉那些明显不对劲的数据。我刚开始做项目时,总觉得这步可有可无,直到有一次模型预测结果完全偏离常识……嗯,后来发现是数据里混了一堆乱码。

常见的脏数据有这几种:

  • 重复数据:同一个样本出现多次,会放大它的影响
  • 异常值:比如年龄填了 200 岁,明显不合理
  • 格式不一致:日期有的是 "2024-01-01",有的是 "01/01/2024"
  • 逻辑错误:比如 "入职日期" 早于 "出生日期"

我的习惯:拿到数据后,先用 df.info()df.describe() 扫一眼。数值列的 min/max 如果离谱,基本就有问题了。

二、缺失值处理——别让空值毁了你的模型

缺失值,每个做 ML 的人都会遇到。我见过有人直接删掉所有含缺失值的行,结果样本量少了 40%,模型直接废了。

怎么处理?看情况:

缺失比例 推荐做法 适用场景
< 5% 直接删除该行 数据量充足时
5% - 20% 均值/中位数/众数填充 数值型用均值,偏态分布用中位数
20% - 50% 模型预测填充 用其他特征预测缺失值
> 50% 删除该特征 信息量太少,留着也没用

我曾经踩过的坑:有一次处理用户收入数据,直接用均值填充缺失值。结果模型训练出来,低收入人群的预测完全不准。后来才发现,收入分布是严重偏态的,应该用中位数才对。

代码示例:

# 均值填充
df['age'].fillna(df['age'].mean(), inplace=True)

# 中位数填充
df['income'].fillna(df['income'].median(), inplace=True)

# 众数填充(适用于类别特征)
df['gender'].fillna(df['gender'].mode()[0], inplace=True)

三、特征缩放——把不同量纲拉到同一水平

为什么要做特征缩放?你想想看,年龄范围是 0-100,收入范围是 0-1000000。如果不缩放,模型会默认收入比年龄重要 10000 倍。这合理吗?当然不合理。

两种主流方法:

标准化(Standardization)

公式:z = (x - μ) / σ

结果:均值为 0,标准差为 1

适用:数据近似正态分布时效果最好

归一化(Normalization)

公式:x' = (x - min) / (max - min)

结果:范围在 [0, 1] 之间

适用:数据有明确边界时,比如像素值 0-255

我个人习惯:如果不知道选哪个,先用标准化。它在大多数场景下表现更稳定。归一化对异常值太敏感,一个极端值就能把整个范围拉变形。

代码示例:

from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 标准化
scaler_std = StandardScaler()
X_std = scaler_std.fit_transform(X)

# 归一化
scaler_mm = MinMaxScaler()
X_mm = scaler_mm.fit_transform(X)

四、类别特征编码——让机器看懂文字

机器学习模型只认数字,不认文字。所以 "北京"、"上海"、"广州" 这些类别特征,必须转成数字。

三种常用方法:

  • Label Encoding(标签编码):给每个类别一个数字,比如 北京=0, 上海=1, 广州=2。适合有序类别,比如 "小/中/大"。
  • One-Hot Encoding(独热编码):每个类别变成一个 0/1 列。适合无序类别,比如城市名。
  • Target Encoding(目标编码):用目标变量的均值来编码。适合高基数类别,比如有 1000 个城市。

注意:Label Encoding 用在无序类别上会出问题。比如 "北京=0, 上海=1, 广州=2",模型会认为 "广州" 比 "北京" 大,这完全没道理。

代码示例:

from sklearn.preprocessing import LabelEncoder, OneHotEncoder

# Label Encoding
le = LabelEncoder()
df['city_encoded'] = le.fit_transform(df['city'])

# One-Hot Encoding
df = pd.get_dummies(df, columns=['city'], prefix='city')

知识体系总览

下面这张图,是我自己总结的数据预处理全流程。每次做项目前,我都会对照着走一遍,确保没有遗漏。

数据预处理流程总览 原始数据 数据清洗 缺失值处理 特征缩放 类别特征编码 干净、标准化的数据 模型训练 删除/填充/预测 标准化/归一化 Label/One-Hot/Target

好了,数据预处理的基础就这些。记住一句话:预处理做得好,模型训练没烦恼。我在项目里吃过太多亏了,希望你少走弯路。