数据预处理基础:数据清洗、缺失值处理、异常值检测与修正

各位同学,咱们今天聊点实在的。做景气度领先指标,数据预处理这步要是没做好,后面模型再花哨也是白搭。我见过太多人一上来就搞复杂模型,结果数据里一堆脏东西,最后跑出来的结果根本没法看。说白了,数据预处理就是给指标打地基,地基不稳,楼盖得再高也得塌。

数据清洗:先把脏东西筛出去

数据清洗,听起来简单,做起来全是坑。我个人的习惯是,拿到数据第一件事不是看统计量,而是先扫一眼原始数据长什么样。你想想看,宏观经济数据里经常出现什么?重复值、格式不统一、单位混乱,这些都得先处理掉。

核心原则:清洗不是删数据,而是让数据变得可用。能修的就修,实在修不了的再考虑删除。

我在项目中遇到过最典型的问题:某个月份的工业增加值数据,因为统计口径调整,突然跳了个大台阶。这种数据你要是直接扔进模型,模型会以为经济突然起飞了,其实只是统计方法变了。怎么办?

  • 重复值处理:检查是否有完全相同的行记录,通常用df.duplicated()就能搞定
  • 格式统一:日期格式、数值格式、单位,必须统一。比如有的数据用"亿",有的用"万",不统一就是灾难
  • 逻辑校验:比如"固定资产投资完成额"不可能为负数,出现负值就是录入错误
# 我常用的数据清洗代码片段
import pandas as pd
import numpy as np

# 加载数据
df = pd.read_csv('macro_data.csv')

# 检查重复值
print(f"重复行数: {df.duplicated().sum()}")

# 统一日期格式
df['date'] = pd.to_datetime(df['date'], format='%Y%m')

# 逻辑校验:剔除明显异常
df = df[df['value'] >= 0]  # 剔除负值

缺失值处理:别让空值毁了你的指标

宏观经济数据,缺失值简直是家常便饭。统计局有时候会延迟发布数据,或者干脆某个指标就不公布了。这时候怎么办?

我个人把缺失值处理分成三步走:先看缺失比例,再看缺失模式,最后选处理方法。

缺失比例 建议处理方式 适用场景
< 5% 插值法(线性/样条) 数据波动平稳,缺失点少
5% - 20% 前向填充 + 后向填充 时间序列数据,趋势明显
20% - 40% 模型预测填充(如ARIMA) 有较强的周期性或趋势
> 40% 考虑剔除该变量 缺失太多,填充意义不大

小技巧:我曾经处理过一组PMI数据,中间有3个月缺失。直接用线性插值?不行,因为PMI有明显的季节性。我用了X-13ARIMA-SEATS做季节调整后再插值,效果好了很多。

嗯,这里要注意:千万别用均值填充时间序列数据。为什么?因为宏观经济数据有趋势和周期,均值填充会破坏数据的动态结构。你想想看,GDP数据用均值填充,那趋势线直接就平了,还怎么做景气度分析?

# 缺失值处理示例
# 前向填充 + 后向填充
df['value'] = df['value'].ffill().bfill()

# 线性插值
df['value'] = df['value'].interpolate(method='linear')

# 季节性插值(如果有周期)
df['value'] = df['value'].interpolate(method='spline', order=3)

异常值检测与修正:揪出那些"离谱"的数据点

异常值检测,说白了就是找出那些"不太对劲"的数据。我刚开始做量化的时候,有一次跑模型,结果R²高得离谱,0.99。我当时还挺高兴,后来一查,原来是某个数据点录入时多了一个零,把整个回归结果带偏了。

从那以后,我养成了一个习惯:每次建模前,必做异常值检测。

常用的检测方法

  • 3σ原则:适用于正态分布的数据,超过均值±3倍标准差就算异常
  • 箱线图法:用IQR(四分位距)来判定,超过Q1-1.5*IQR或Q3+1.5*IQR就算异常
  • 移动平均法:对于时间序列,看当前值是否偏离移动平均线太远

避坑指南:我曾经在分析工业增加值时,用3σ原则检测异常值,结果把2008年金融危机期间的数据全标成了异常。但那些数据恰恰是真实的经济波动,不是录入错误。所以,异常值检测一定要结合业务背景来判断,不能机械地套公式。

修正策略

发现异常值后,怎么处理?我的经验是分情况讨论:

  1. 录入错误:直接修正,比如多了一个零就删掉
  2. 真实极端值:保留,但做缩尾处理(Winsorize),比如把极端值拉到99%分位数
  3. 结构性突变:分段处理,比如2008年金融危机前后的数据分开建模
# 异常值检测与修正
from scipy import stats

# 3σ原则
z_scores = np.abs(stats.zscore(df['value']))
outliers = z_scores > 3

# 缩尾处理(Winsorize)
lower = df['value'].quantile(0.01)
upper = df['value'].quantile(0.99)
df['value_winsorized'] = df['value'].clip(lower, upper)

# 移动平均法检测
df['ma_3'] = df['value'].rolling(window=3).mean()
df['deviation'] = np.abs(df['value'] - df['ma_3']) / df['ma_3']
outliers_ma = df['deviation'] > 0.2  # 偏离超过20%算异常

知识体系总览

下面这张图,是我自己总结的数据预处理流程。每次做新项目,我都会先过一遍这个流程,确保没有遗漏。

数据预处理流程框架 原始数据 数据清洗 重复值处理 格式统一 缺失值处理 插值法 前向/后向填充 异常值检测 3σ原则 箱线图法 异常值修正 缩尾处理 分段建模 关键原则 1. 先看数据再动手 2. 能修不删 3. 结合业务背景 4. 保留处理记录 5. 多次迭代验证

最后说一句,数据预处理没有标准答案。同样的数据,不同的人处理方式可能完全不同。关键是要理解你的数据、理解你的业务场景。我做了这么多年,最大的体会就是:预处理花的时间越多,后面建模就越省心。别急着跑模型,先把数据收拾利索了。

专注资料整理