第四节:数据清洗与预处理

数据清洗这事儿,我做了快十年了。说实话,很多新手觉得这步枯燥,恨不得直接跑模型。但我告诉你——数据不干净,模型跑出来就是垃圾。我在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个亿,那就得处理。

我常用的方法有两个:

  1. 3σ原则:超出均值±3倍标准差的值,标记为异常。
  2. 箱线图法:超出上下四分位数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 知识体系总览

下面这张图,是我自己梳理的数据清洗流程。你看一眼,心里就有谱了:

数据清洗与预处理流程 原始数据 个股资金流向 缺失值处理 0填充 / 前值填充 异常值检测 3σ / 箱线图法 统一板块名称 映射字典 + 人工校验 计算资金净流入/流出 个股求和 → 板块汇总 清洗后数据 板块日度资金流向 个股级别处理 板块级别汇总 最终输出

你看,整个流程其实就六步。但每一步都有坑,尤其是板块名称统一那步,我建议你多花点时间。数据清洗占整个项目70%的时间,这话一点不夸张。

避坑指南:我曾经因为偷懒,直接用字符串匹配去统一板块名称,结果「半导体设备」被匹配成了「半导体」,「白酒」和「啤酒」混在了一起。后来我学乖了——先人工整理一份完整的映射表,再写代码批量处理。

好了,数据清洗这块就聊到这儿。记住一句话:干净的数据,是量化交易的基石。下一节咱们聊聊怎么用这些清洗好的数据,构建板块轮动信号。

专注资料整理