3、数据获取与清洗:使用akshare获取A股数据、处理缺失值与异常值、数据对齐与重采样
做量化投资,尤其是指数增强策略,第一步就是搞定数据。我见过太多人把精力全花在模型上,结果数据源就有问题,最后模型跑出来的结果根本没法用。说白了,数据质量决定了你策略的天花板。
这一章,咱们就聊聊怎么用 akshare 这个库拿到A股数据,然后怎么把那些脏数据洗干净。嗯,这里要注意,清洗这一步往往比获取更花时间。
3.1 为什么选akshare?
市面上能拿A股数据的库不少,比如 tushare、baostock。我个人习惯用 akshare,原因很简单:它免费,而且接口覆盖全。从日线到分钟线,从个股到指数,甚至龙虎榜数据都能拿。你想想看,对于一个刚起步的量化项目,这能省下多少成本。
不过它也有缺点——数据源是爬虫抓取的,偶尔会断。我在项目中遇到过几次,某天突然拿不到某只股票的数据,后来发现是对方网站改版了。所以我的建议是:生产环境一定要做数据缓存和备份。
3.2 安装与基础用法
安装很简单,一行命令搞定:
pip install akshare
然后就可以获取数据了。比如拿上证指数的历史日线:
import akshare as ak
# 获取上证指数日线数据
df = ak.stock_zh_index_daily(symbol="sh000001")
print(df.head())
输出大概长这样:
| date | open | close | high | low | volume |
|---|---|---|---|---|---|
| 2023-01-03 | 3087.99 | 3116.51 | 3129.09 | 3087.99 | 2.89e8 |
| 2023-01-04 | 3119.46 | 3123.52 | 3128.54 | 3115.42 | 2.63e8 |
拿个股数据也类似,比如贵州茅台:
df_stock = ak.stock_zh_a_hist(symbol="600519", period="daily")
print(df_stock.head())
time.sleep() 控制频率,别把对方服务器搞崩了。我曾经一口气拉了5000只股票,结果被ban了IP。
3.3 处理缺失值与异常值
数据拿到手,第一件事就是检查缺失值。你想想看,如果某只股票某天停牌,那天的价格就是NaN。如果不处理,模型会直接报错。
我一般用 pandas 来做清洗:
import pandas as pd
# 检查缺失值
print(df.isnull().sum())
# 处理方式1:向前填充(适合停牌数据)
df.fillna(method='ffill', inplace=True)
# 处理方式2:删除缺失行(适合少量缺失)
df.dropna(inplace=True)
异常值更隐蔽。比如某只股票突然涨了1000%,那大概率是数据错误。我常用的方法是 3-sigma 法则:
# 计算收益率
df['return'] = df['close'].pct_change()
# 找出超过3倍标准差的值
mean = df['return'].mean()
std = df['return'].std()
outliers = df[(df['return'] > mean + 3*std) | (df['return'] < mean - 3*std)]
# 将这些异常值替换为NaN,然后填充
df.loc[outliers.index, 'return'] = None
df['return'].fillna(method='ffill', inplace=True)
3.4 数据对齐与重采样
做指数增强,你需要把多个股票的数据对齐到同一个时间轴上。比如你有3000只股票,有的股票在2020年1月1日有数据,有的没有。这时候就需要对齐。
我习惯用 pandas 的 reindex 方法:
# 假设我们有两只股票的数据
stock_a = df_a.set_index('date')['close']
stock_b = df_b.set_index('date')['close']
# 合并并对齐
combined = pd.concat([stock_a, stock_b], axis=1, keys=['stock_a', 'stock_b'])
combined.dropna(inplace=True) # 删除任何一只股票缺失的日期
重采样也很常用。比如你拿到的日线数据,但策略需要周线信号。这时候就用 resample:
# 将日线重采样为周线
weekly = df.resample('W', on='date').agg({
'open': 'first',
'close': 'last',
'high': 'max',
'low': 'min',
'volume': 'sum'
})
为什么要重采样?说白了,不同频率的数据会带来不同的信号。日线噪声大,周线更平滑。我个人习惯先用日线做因子计算,最后再重采样到周线或月线做回测。
3.5 本章核心逻辑图
下面这张图概括了数据获取与清洗的完整流程,从原始数据到可用的干净数据集:
3.6 避坑指南
最后,分享几个我踩过的坑:
- 数据源不稳定:akshare 偶尔会报错,建议加 try-except 和重试机制。
- 复权问题:akshare 默认返回的是不复权数据。做回测一定要用后复权,否则分红送股会扭曲收益率。
- 停牌处理:停牌期间的数据是缺失的,用前向填充最合理。千万别用均值填充,那会引入未来信息。
- 时间戳对齐:不同股票的交易日期可能不同(比如有的股票在某个交易日停牌),对齐后一定要检查数据量是否合理。
嗯,数据清洗这部分就聊到这儿。记住一句话:垃圾进,垃圾出。数据搞定了,后面的模型才能跑得稳。