第四节:数据清洗与预处理
数据清洗这事儿,我做了快十年了。说实话,很多新手觉得这步枯燥,恨不得直接跑模型。但我告诉你——数据不干净,模型跑出来就是垃圾。我在2018年做过一个回测,就因为板块名称没统一,结果把「半导体」和「芯片」当成了两个板块,资金流向全算错了,白白浪费了两周时间。
今天咱们就聊聊,怎么把原始数据收拾得服服帖帖。
4.1 处理缺失值:别急着删
拿到数据第一件事,看看有没有空值。我习惯用 df.isnull().sum() 快速扫一眼。
import pandas as pd
import numpy as np
# 假设df是原始数据
print(df.isnull().sum())
缺失值怎么处理?分情况讨论:
- 资金流向字段缺失:如果某只股票当天停牌,资金流向就是空。我一般用0填充,因为停牌日确实没有交易。
- 板块归属缺失:这个要小心。我曾经遇到过一只股票,同花顺和东方财富给的板块不一样。我的做法是——查一下这只股票的主营业务,手动补上。
- 日期缺失:非交易日缺失是正常的,不用管。但如果是交易日缺失,可能是数据源漏了,建议重新拉取。
我的小技巧:对于资金流向的缺失值,别用均值填充。你想啊,某天资金净流入为0和均值填充,对后续计算板块净流入的影响完全不同。我一般用0填充,或者用前一天的数值。
4.2 异常值检测:别让一根大阳线骗了你
异常值在资金流向数据里特别常见。比如某只股票突然拉了个涨停,资金净流入暴增10倍。这算异常吗?不一定。但如果是因为数据录入错误,把100万录成了1个亿,那就得处理。
我常用的方法有两个:
- 3σ原则:超出均值±3倍标准差的值,标记为异常。
- 箱线图法:超出上下四分位数1.5倍IQR的值,视为异常。
# 用箱线图法检测异常值
Q1 = df['net_inflow'].quantile(0.25)
Q3 = df['net_inflow'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['net_inflow'] < lower_bound) | (df['net_inflow'] > upper_bound)]
print(f"发现 {len(outliers)} 个异常值")
注意:别一看到异常值就删。我遇到过一只股票,连续三天资金净流入异常大,结果一查,是机构在密集建仓。这种「异常」其实是信号,不是错误。
4.3 统一板块名称:最坑的环节
这块我吃过太多亏了。不同数据源对板块的命名五花八门:
| 数据源A | 数据源B | 统一名称 |
|---|---|---|
| 半导体 | 芯片 | 半导体 |
| 白酒 | 酿酒行业 | 白酒 |
| 新能源车 | 新能源汽车 | 新能源汽车 |
| 光伏 | 太阳能 | 光伏 |
我的做法是建一个映射字典:
sector_mapping = {
'芯片': '半导体',
'半导体': '半导体',
'酿酒行业': '白酒',
'白酒': '白酒',
'新能源汽车': '新能源汽车',
'新能源车': '新能源汽车',
'太阳能': '光伏',
'光伏': '光伏'
}
df['sector'] = df['sector'].map(sector_mapping)
嗯,这里要注意——映射完之后,一定要检查有没有漏掉的。我习惯用 df['sector'].unique() 看一眼,确保所有板块名称都映射上了。
4.4 计算资金净流入/净流出
终于到核心了。资金净流入的计算公式其实很简单:
净流入 = 主动买入金额 - 主动卖出金额
但实际数据里,我们拿到的往往是「大单净流入」「小单净流入」这些细分数据。我个人习惯这样算:
# 假设数据包含以下字段
# large_buy: 大单买入金额
# large_sell: 大单卖出金额
# small_buy: 小单买入金额
# small_sell: 小单卖出金额
df['net_large'] = df['large_buy'] - df['large_sell']
df['net_small'] = df['small_buy'] - df['small_sell']
df['net_total'] = df['net_large'] + df['net_small']
然后按板块和日期汇总:
sector_flow = df.groupby(['date', 'sector'])['net_total'].sum().reset_index()
sector_flow.columns = ['date', 'sector', 'sector_net_flow']
这样,我们就得到了每个板块每天的资金净流入/净流出。
关键点:计算板块净流入时,一定要用「个股净流入求和」,而不是用「板块指数涨跌幅」来反推。前者是真实资金,后者是价格变化,两码事。
4.5 知识体系总览
下面这张图,是我自己梳理的数据清洗流程。你看一眼,心里就有谱了:
你看,整个流程其实就六步。但每一步都有坑,尤其是板块名称统一那步,我建议你多花点时间。数据清洗占整个项目70%的时间,这话一点不夸张。
避坑指南:我曾经因为偷懒,直接用字符串匹配去统一板块名称,结果「半导体设备」被匹配成了「半导体」,「白酒」和「啤酒」混在了一起。后来我学乖了——先人工整理一份完整的映射表,再写代码批量处理。
好了,数据清洗这块就聊到这儿。记住一句话:干净的数据,是量化交易的基石。下一节咱们聊聊怎么用这些清洗好的数据,构建板块轮动信号。