第一章:数据质量初探——缺失值、异常值、重复数据、时间戳错乱

大家好,我是老张。干量化数据这行快十年了,踩过的坑比吃过的盐还多。

今天咱们聊聊数据质量。你可能觉得这话题太基础,但说实话,我见过太多团队在数据清洗上翻车。有一次,一个同事跑了一整夜的策略回测,结果发现收益率高得离谱——后来一查,是某交易所的行情数据里混进了几根「幽灵K线」。

嗯,这种事,你迟早也会遇到。

1.1 缺失值:数据里的「黑洞」

缺失值是最常见的问题。说白了,就是某个时间点的数据没拿到。

为什么会缺失?

  • 网络波动,数据包丢了
  • 交易所服务器宕机
  • 数据源本身就不完整(比如某些小币种)

怎么处理?

我个人习惯分三步走:

  1. 先检测:用 df.isnull().sum() 看看哪些列有缺失
  2. 再分析:缺失比例超过 5% 的,我建议直接扔掉那段时间的数据
  3. 最后填充:少量缺失可以用前向填充(ffill)或线性插值

避坑指南

我曾经在回测时用了后向填充(bfill),结果把未来的价格填进了历史数据里。嗯,那次的夏普比率直接翻倍了——全是假的。

# 缺失值处理示例
import pandas as pd

# 检测缺失
print(df.isnull().sum())

# 前向填充(用上一个有效值填充)
df['close'].fillna(method='ffill', inplace=True)

# 线性插值(适合连续缺失)
df['close'].interpolate(method='linear', inplace=True)

1.2 异常值:那些「离谱」的价格

你想想看,比特币突然从 3 万跳到 100 万,然后又跌回 3 万——这种事在真实行情里偶尔会发生。

怎么识别?

  • 3σ 原则:超过均值 ±3 个标准差的,基本就是异常
  • IQR 方法:四分位距法,适合非正态分布的数据
  • 业务规则:比如价格不能为负,成交量不能为 0

我的经验

别一上来就删异常值。有一次我发现某只股票在收盘前 3 秒出现巨量成交——后来查证是机构调仓,那是真实数据。删了就亏大了。

# 异常值检测:IQR 方法
Q1 = df['close'].quantile(0.25)
Q3 = df['close'].quantile(0.75)
IQR = Q3 - Q1

# 定义异常范围
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 标记异常
df['is_outlier'] = (df['close'] < lower_bound) | (df['close'] > upper_bound)

1.3 重复数据:看似无害的「双胞胎」

重复数据最坑人。你看着数据量挺大,其实有一半是重复的。

常见场景

  • 同一根 K 线被推送了两次
  • 数据采集脚本重复写入
  • 不同数据源合并时产生重复

怎么处理?

我建议用 df.duplicated() 先看看重复情况,然后用 df.drop_duplicates() 清理。注意要指定 subset 参数,别把不同时间点的数据误删了。

注意

重复数据会影响你的统计指标。比如计算平均成交量时,重复数据会让结果偏高。我曾经因为这个原因,把某只股票的流动性评估搞错了。

# 检测重复
print(df.duplicated(subset=['timestamp', 'symbol']).sum())

# 删除重复,保留第一次出现
df.drop_duplicates(subset=['timestamp', 'symbol'], keep='first', inplace=True)

1.4 时间戳错乱:最隐蔽的「杀手」

时间戳错乱是数据清洗里最头疼的问题。为什么?因为它很难一眼看出来。

常见问题

  • 时间戳格式不统一(有的用毫秒,有的用秒)
  • 时区没对齐(UTC vs 北京时间)
  • 数据乱序(后发的数据先到)

我的处理流程

  1. 统一转为 UTC 时间戳(毫秒级)
  2. 按时间戳排序
  3. 检查时间间隔是否均匀
  4. 发现跳跃或回退,标记出来

避坑指南

我曾经在合并美股和港股数据时,没注意时区差异。结果美股收盘时间比港股开盘还晚——那天的策略信号全乱了。后来我强制所有数据统一用 UTC+0。

# 时间戳标准化
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)

# 排序
df.sort_values('timestamp', inplace=True)

# 检查时间间隔
df['time_diff'] = df['timestamp'].diff().dt.total_seconds()
print(df['time_diff'].describe())

1.5 知识体系总览

下面这张图,是我自己总结的数据质量检查流程。你照着做,基本能避开 90% 的坑。

数据质量检查流程 原始行情数据 步骤1:缺失值检测与填充 步骤2:异常值识别与处理 步骤3:重复数据清理 步骤4:时间戳对齐与排序

1.6 实战建议

最后,给你几个实在的建议:

  • 先看后动:拿到数据先做描述性统计,看看最大值、最小值、缺失比例
  • 保留原始数据:永远别在原数据上改,复制一份再处理
  • 记录每一步:你删了多少行、填充了多少值,都记下来。方便复盘
  • 自动化检查:写个脚本,每天跑完数据自动生成质量报告

我的习惯

我每次处理完数据,都会随机抽 100 条手动核对。虽然麻烦,但能发现很多自动化检查漏掉的问题。嗯,这招是当年被坑出来的经验。

好了,数据质量这块就聊到这儿。记住一句话:垃圾数据进,垃圾策略出。花 80% 的时间清洗数据,剩下 20% 的时间建模——这才是量化交易的正确姿势。


公众号:蓝海资料掘金营,微信deep3321