第1章:数据获取与清洗——量化建模的第一步

做量化投资,数据就是你的原材料。没有干净的数据,再牛的模型也是白搭。我刚开始做量化那会儿,就吃过这个亏——拿到的数据直接跑回测,结果收益曲线漂亮得不行,实盘一跑就崩。后来才发现,原来是数据里藏着未来信息。

这一章,咱们就聊聊数据获取与清洗的那些事儿。说白了,就是怎么把股票数据搞到手,再把它收拾得服服帖帖。

核心要点:数据质量决定模型上限。花80%的时间做数据清洗,一点都不夸张。

1.1 用pandas-datareader获取股票数据

我个人习惯用 pandas-datareader 来拉数据。这个库封装了多个数据源接口,用起来很方便。你想想看,一行代码就能拿到股票的历史行情,多省事。

import pandas as pd
import pandas_datareader.data as web
import datetime

# 设置时间范围
start = datetime.datetime(2020, 1, 1)
end = datetime.datetime(2023, 12, 31)

# 获取贵州茅台股票数据
df = web.DataReader('600519.SS', 'yahoo', start, end)
print(df.head())

这里要注意,A股代码在雅虎财经后面要加后缀:上海交易所加 .SS,深圳交易所加 .SZ。我在项目中遇到过,有人忘了加后缀,结果拉了一堆空数据回来,排查了半天。

交易所 代码后缀 示例
上海证券交易所 .SS 600519.SS
深圳证券交易所 .SZ 000001.SZ

小技巧:如果雅虎数据源不稳定,可以试试 stooqalphavantage。我一般会备两个数据源,一个挂了马上切另一个。

1.2 数据缺失值处理

拿到的数据,十有八九是有缺失的。为什么?停牌、节假日、数据源本身的问题,都会导致缺失。嗯,这里要注意,缺失值处理不当,会直接影响后续计算。

常见的处理方法有几种:

  • 直接删除:缺失比例小的时候可以用,但别删太多,否则样本量不够。
  • 向前填充:用上一个交易日的数据填充,适合价格类数据。我个人比较推荐这个。
  • 插值法:线性插值或时间插值,适合成交量这类波动较大的数据。
# 检查缺失值
print(df.isnull().sum())

# 向前填充(最常用)
df.fillna(method='ffill', inplace=True)

# 或者用插值法
df.interpolate(method='linear', inplace=True)

避坑指南:我曾经犯过一个错误——对收益率序列用了向前填充。结果呢?收益率被重复复制,回测结果严重失真。记住,收益率数据不能用填充,最好直接删除缺失行。

1.3 异常值检测与处理

异常值,说白了就是那些离谱的数据点。比如某只股票一天涨了1000%,这明显是数据录入错误。你想想看,A股有涨跌停限制,怎么可能一天翻十倍?

常用的检测方法:

  1. 3σ原则:超出均值±3倍标准差的数据,视为异常。
  2. 箱线图法:用四分位数来识别异常值,更稳健。
  3. 业务规则:比如涨跌幅超过10%的,直接标记。
# 用3σ原则检测异常值
mean = df['Close'].mean()
std = df['Close'].std()
outliers = df[(df['Close'] > mean + 3*std) | (df['Close'] < mean - 3*std)]

# 处理方式:用中位数替换
median = df['Close'].median()
df.loc[outliers.index, 'Close'] = median

我在项目中遇到过,某只小盘股因为数据源问题,连续几天出现价格跳空。用3σ检测出来之后,我选择了用前后两天的均值替换。效果还不错。

1.4 数据对齐与重采样

做多因子模型时,经常要把不同频率的数据对齐。比如日线数据和周线数据,怎么对齐?重采样就是干这个的。

数据对齐的核心思想:以最细粒度的数据为基准,其他数据向它对齐。

# 重采样:日线转周线
weekly = df.resample('W').agg({
    'Open': 'first',
    'High': 'max',
    'Low': 'min',
    'Close': 'last',
    'Volume': 'sum'
})

# 多只股票数据对齐
# 假设我们有两只股票的数据
stock1 = web.DataReader('600519.SS', 'yahoo', start, end)['Close']
stock2 = web.DataReader('000001.SZ', 'yahoo', start, end)['Close']

# 合并并自动对齐
combined = pd.concat([stock1, stock2], axis=1, keys=['茅台', '平安'])
combined.dropna(inplace=True)  # 删除对齐后仍有缺失的行

经验之谈:重采样时,开盘价用第一个值,收盘价用最后一个值,最高价取最大值,最低价取最小值,成交量求和。这个规则我用了好多年,没出过问题。

知识体系总览

下面这张图,把本章的核心逻辑串起来了。你可以看到,数据获取是起点,清洗是中间环节,最终得到干净、对齐的数据,才能喂给模型。

数据获取与清洗流程 数据获取 pandas-datareader 缺失值处理 填充 / 删除 / 插值 异常值检测 3σ / 箱线图 / 业务规则 数据对齐 多股票 / 多频率对齐 重采样 日线→周线 / 月线 干净数据 可直接用于建模 数据清洗不是一次性工作,需要反复迭代验证

数据清洗这块,我建议你养成一个习惯:每做一步清洗,都保存一个中间结果。这样万一后面发现数据有问题,还能回溯到上一步。我曾经因为没保存中间结果,重新拉了一遍数据,浪费了大半天时间。

本章小结:数据获取用pandas-datareader,缺失值处理优先向前填充,异常值检测结合统计方法和业务规则,数据对齐和重采样是建模前的最后一步。把这四步走扎实了,后面的建模工作才能顺利开展。

专注资料整理