首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python 量化数据清洗与预处理实战

Python 量化数据清洗与预处理实战

原创
作者头像
gavin1024
发布2026-09-20 15:56:33
发布2026-09-20 15:56:33
230
举报

量化交易中的数据清洗与预处理,是决定策略成败的隐形关键环节,核心工作包括六步:处理缺失值、去除重复数据、修正异常值、统一时间序列对齐、处理复权问题、以及规范数据格式与类型。这些工作看似枯燥,却直接关系到回测结果是否可信——脏数据喂出来的策略,再漂亮的曲线也是假象。本文用 pandas 演示量化数据清洗的实战流程,带你把一份"脏"的原始行情数据整理成可以放心用于回测的干净数据。

一、被严重低估的一步

在量化的所有环节里,数据清洗大概是最不起眼、也最被新手忽视的一步。大家都想写酷炫的策略、跑漂亮的回测,谁愿意花时间去清理枯燥的数据?

但我做量化这些年最深的体会之一就是:数据质量决定了策略的上限。 有句话在圈子里流传很广——"垃圾进,垃圾出"(Garbage In, Garbage Out)。你喂给策略的数据是脏的,那不管你的策略逻辑多精妙、回测曲线多好看,结果都是不可信的假象。

所以这篇我们就来认认真真地做数据清洗。别嫌枯燥,这一步做扎实,能帮你避开大量"回测赚钱、实盘亏钱"的坑。

二、先加载数据并做个体检

拿到一份原始数据,第一件事不是急着用,而是先"体检"——看看它有没有毛病。

代码语言:python
复制
import pandas as pd
import numpy as np

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

# 体检:看看数据的基本情况
print(df.info())        # 查看列、数据类型、非空数量
print(df.describe())    # 查看数值分布
print(df.isnull().sum())  # 查看每列缺失多少

info() 看结构和缺失,describe() 看数值有没有明显异常,isnull().sum() 看缺失情况。这三行下去,数据有什么问题基本心里有数了。

三、第一步:处理缺失值

缺失值是最常见的数据问题——某天的价格没记录、某个字段是空的。处理方式要根据情况来。

代码语言:python
复制
# 先转换日期并排序(时间序列处理的前提)
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values("date").reset_index(drop=True)

# 方式一:价格缺失,用前一个有效值填充(前向填充)
df["close"] = df["close"].ffill()

# 方式二:如果缺失太多、无法填充,直接删除该行
df = df.dropna(subset=["close"])

对行情数据,价格的少量缺失通常可以用前向填充(用上一个有效价格补上);但如果缺失严重,硬填反而会引入错误,不如删掉。怎么处理取决于数据的实际情况,没有万能公式。

四、第二步:去除重复数据

数据源有时会给出重复的记录,比如同一天出现两条。重复数据会让回测结果失真,必须去掉。

代码语言:python
复制
# 按日期去重,保留第一条
df = df.drop_duplicates(subset=["date"], keep="first").reset_index(drop=True)

print("去重后数据条数:", len(df))

去重时要想清楚"以什么为唯一标准"——对日线数据,通常一个日期只应有一条记录。

五、第三步:修正异常值

异常值是最隐蔽的坑——比如某天价格突然变成 0、或者是明显错误的天价。这些异常如果不处理,会严重扭曲回测。

代码语言:python
复制
# 检查明显异常:价格为 0 或负数
abnormal = df[df["close"] <= 0]
print("异常记录数:", len(abnormal))

# 处理:把异常价格标记为缺失,再用前向填充
df.loc[df["close"] <= 0, "close"] = np.nan
df["close"] = df["close"].ffill()

# 也可以检查涨跌幅是否异常(比如单日涨跌超过某个不合理阈值)
df["pct"] = df["close"].pct_change()
extreme = df[df["pct"].abs() > 0.5]  # 单日波动超过 50% 需警惕
print("极端波动记录数:", len(extreme))

异常值检测没有标准答案,需要结合业务常识判断。关键是保持警惕——一份看起来正常的数据里,可能藏着几个足以毁掉回测的异常点。

六、第四步:时间序列对齐

量化数据是时间序列,正确的时间处理至关重要。要确保日期格式统一、按时间排序、必要时对齐到统一的时间频率。

代码语言:python
复制
# 确保按时间排序(前面已做)
# 如果需要对齐到连续的交易日/自然日,可以设置日期索引
df = df.set_index("date")

# 示例:如果要重采样成规整的频率(按需,非必须)
# df = df.resample("D").ffill()  # 按自然日对齐并前向填充

print(df.index.min(), "到", df.index.max())

时间对齐的意义在于:当你处理多个标的、或要把不同数据源拼在一起时,时间轴必须对得上,否则计算会出错。

七、第五步:处理复权问题

这是股票数据特有、也极易被新手忽略的坑。当股票发生分红、送股时,价格会"跳空",如果用未复权的价格算收益,会得到错误结果。

复权处理的核心思想是:把因为分红送股导致的价格跳变"还原",让价格序列在计算收益时保持连续性。实际操作中,通常直接获取前复权或后复权的价格数据来用。

代码语言:python
复制
# 如果数据源提供了复权价格列(如 adj_close),优先使用它
if "adj_close" in df.columns:
    df["price_for_calc"] = df["adj_close"]
else:
    df["price_for_calc"] = df["close"]
    # 注意:用未复权价格算长期收益可能有误差

记住:算收益率时,一定要用复权后的价格,否则分红送股当天会出现虚假的"暴跌",让回测结果完全失真。

八、第六步:规范格式与类型

最后,确保数据的格式和类型规范,为后续计算扫清障碍。

代码语言:python
复制
# 确保价格是数值类型
df["price_for_calc"] = pd.to_numeric(df["price_for_calc"], errors="coerce")

# 再检查一遍是否还有缺失
df = df.dropna(subset=["price_for_calc"])

# 保存清洗后的干净数据
df.to_csv("clean_stock_data.csv")
print("清洗完成,干净数据已保存")

到这里,一份可以放心用于回测的干净数据就整理好了。

九、数据清洗流程一览

我把整个清洗流程整理成一张表:

步骤

处理内容

关键方法

缺失值

填充或删除空值

ffill、dropna

重复数据

去除重复记录

drop_duplicates

异常值

检测并修正异常

条件筛选、标记填充

时间对齐

排序、对齐时间轴

sort_values、resample

复权处理

还原分红送股影响

使用复权价格

格式规范

统一数据类型

to_numeric

结尾

量化数据的清洗与预处理,是一项被严重低估却极其关键的工作。处理缺失、去重、修异常、对齐时间、处理复权、规范格式——这六步做扎实了,你的回测才有可信的基础。记住那句朴素的真理:垃圾进,垃圾出。愿意在数据上多花功夫的人,往往能避开最多的坑。

当你要处理大量历史数据、或让数据抓取和清洗流程长期自动运行时,本地环境可能力不从心。这时可以把数据处理程序放到腾讯云云服务器 CVM 上运行,利用云端的稳定性和存储能力支撑长期任务。腾讯云近期上线了量化交易专题活动,可以了解云服务器如何承载数据抓取、清洗与策略回测的全流程。

风险提示:本文仅为量化交易科普与技术分享,不构成任何投资建议。文中代码仅为教学示例。金融市场存在风险,任何交易策略都可能产生亏损,请结合自身情况谨慎决策。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、被严重低估的一步
  • 二、先加载数据并做个体检
  • 三、第一步:处理缺失值
  • 四、第二步:去除重复数据
  • 五、第三步:修正异常值
  • 六、第四步:时间序列对齐
  • 七、第五步:处理复权问题
  • 八、第六步:规范格式与类型
  • 九、数据清洗流程一览
  • 结尾
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档