3、数据获取与清洗:使用akshare获取A股数据、处理缺失值与异常值、数据对齐与重采样

做量化投资,尤其是指数增强策略,第一步就是搞定数据。我见过太多人把精力全花在模型上,结果数据源就有问题,最后模型跑出来的结果根本没法用。说白了,数据质量决定了你策略的天花板。

这一章,咱们就聊聊怎么用 akshare 这个库拿到A股数据,然后怎么把那些脏数据洗干净。嗯,这里要注意,清洗这一步往往比获取更花时间。

3.1 为什么选akshare?

市面上能拿A股数据的库不少,比如 tusharebaostock。我个人习惯用 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)
注意: 不要机械地删除所有异常值。比如新股上市首日涨44%,那是正常现象。我曾经因为误删这类数据,导致策略回测结果偏差很大。

3.4 数据对齐与重采样

做指数增强,你需要把多个股票的数据对齐到同一个时间轴上。比如你有3000只股票,有的股票在2020年1月1日有数据,有的没有。这时候就需要对齐。

我习惯用 pandasreindex 方法:

# 假设我们有两只股票的数据
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 本章核心逻辑图

下面这张图概括了数据获取与清洗的完整流程,从原始数据到可用的干净数据集:

数据获取与清洗流程 1. 数据获取 akshare接口 2. 缺失值处理 ffill / dropna 3. 异常值处理 3-sigma / 替换 4. 数据对齐 reindex / concat 5. 重采样 日线→周线/月线 ✅ 干净可用的数据集

3.6 避坑指南

最后,分享几个我踩过的坑:

  • 数据源不稳定:akshare 偶尔会报错,建议加 try-except 和重试机制。
  • 复权问题:akshare 默认返回的是不复权数据。做回测一定要用后复权,否则分红送股会扭曲收益率。
  • 停牌处理:停牌期间的数据是缺失的,用前向填充最合理。千万别用均值填充,那会引入未来信息。
  • 时间戳对齐:不同股票的交易日期可能不同(比如有的股票在某个交易日停牌),对齐后一定要检查数据量是否合理。

嗯,数据清洗这部分就聊到这儿。记住一句话:垃圾进,垃圾出。数据搞定了,后面的模型才能跑得稳。


专注资料整理