数据体检:揪出数据里的病灶
六项检查,把上一节埋的三个真实问题一个个挖出来
上一节结尾我说:你存下的 csi300.csv 里,天生带着三个数据问题,其中一个多达 721 天。
今天不讲新道理,就干一件事:像医生一样给数据做体检——六项检查逐项过,把这三个「病灶」全部揪出来。它们分别是:一个 17 天的「空洞」、一天 +9.39% 的「异动」、和 721 天诡异的「零」。
体检完你会发现:三个都不是数据错了,而是各有一段真实的历史。但如果你不体检就直接拿去回测——它们每一个都能把你的结论带进沟里。这就是 q0.4 那句「垃圾进,垃圾出」的实战版。
拿到数据就直接跑策略,像拿到二手车钥匙就直接上高速。
老司机的做法是先绕车一圈:胎压、刹车、机油、里程表有没有被调过——不是怀疑一切,而是知道要看哪几个位置。今天这六项检查,就是数据的「绕车一圈」清单,以后你拿到任何一份行情数据,都先这么绕一遍。
六项体检,逐项跑
接着上一节的 csi300.csv,新建 check_data.py:
import pandas as pd
df = pd.read_csv("csi300.csv", parse_dates=["date"]).set_index("date").sort_index()
# ① 形状:多少行、多少列
print("① 形状:", df.shape)
# ② 缺失值:每列有多少空洞
print("② 缺失值:\n", df.isna().sum())
# ③ 重复:同一天出现两次?
print("③ 重复日期:", df.index.duplicated().sum())
# ④ 日期间隔:相邻两根K线隔了几天
gap = df.index.to_series().diff().dt.days
print("④ 最大间隔:", gap.max(), "天,出现在", gap.idxmax().date())
# ⑤ 极端涨跌:单日涨跌超过6%的日子
ret = df["close"].pct_change()
big = ret[ret.abs() > 0.06]
print("⑤ 单日涨跌>6%:", len(big), "天;最猛一天:",
big.abs().idxmax().date(), round(big[big.abs().idxmax()] * 100, 2), "%")
# ⑥ 可疑的零:成交量为0的天数
zero = df[df["volume"] == 0]
print("⑥ 零成交量:", len(zero), "天",
"" if zero.empty else f"({zero.index.min().date()} → {zero.index.max().date()})")
我在 2026-07 实测的结果,以及每个数字背后的真相:
| 检查 | 实测结果 | 真相 |
|---|---|---|
| ① 形状 | 5959 行 × 5 列 | 正常,二十多年的日线 |
| ② 缺失值 | 全为 0 | 这份数据没有空值,运气不错 |
| ③ 重复日期 | 0 | 干净 |
| ④ 最大间隔 | 17 天(2002-02-25 前) | 🔍 病灶一?——不,是 2002 年春节休市。长假不是数据丢失 |
| ⑤ 极端涨跌 | 46 天;最猛 2002-06-24,+9.39% | 🔍 病灶二?——真实历史:当天宣布停止国有股减持,史称「6·24 行情」。异动≠异常 |
| ⑥ 零成交量 | 721 天(2002-01-04 → 2004-12-31) | 🔍 病灶三:真问题!见下文 |
721 天的零,是怎么回事
三个「病灶」里,前两个体检完发现是「虚惊」——但第三个是真的:2002 到 2004 年底,整整 721 天成交量全是 0。
真相是:沪深300 指数 2005 年 4 月 8 日才正式发布。你拉到的 2005 年之前的行情,是指数公司事后回溯计算的——价格能回算,但当年并不存在这个指数的「成交量」,所以数据源填了 0。
这意味着什么?如果你的策略用到成交量(比如「放量突破买入」),拿这段数据回测,2002–2004 年的结果全是垃圾——量能永远是 0,策略在那三年里根本不是在交易真实世界。
处理很简单,但必须是你知情后的主动选择:
# 只保留指数正式发布后的数据(2005-04-08 起)
df = df[df.index >= "2005-04-08"]
这就是体检的意义:数据不体检,你连自己在用「回溯编制的历史」都不知道。
两个新手常见的误伤:
- 看到日期断了 17 天就去「补数据」——那是春节,市场真的没开门。交易日历本来就不连续,周末、节假日都是合法空洞。
- 看到 +9.39% 就当「异常值」删掉或截断——那是真实发生的行情。你删掉的不是噪声,是历史;而策略在实盘里恰恰要经历这种日子。
体检的产出不是「删掉一切可疑值」,而是给每个可疑值找到解释:能解释的保留,解释不了的(比如那 721 个零)再决定怎么处理。
很多人以为「指数是官方编的,数据总靠谱吧」——你今天亲手证明了:连沪深300 都有三年的回溯段,量能字段整段为零。
这不是数据源的错(价格回算是行业惯例),但它提醒你一件事:任何数据,在你验证它之前,都只是「据称如此」。下次有人给你一份「二十年回测」,你可以先问一句:数据的前几年,是真实交易出来的,还是回溯编制的?——这一问,就很内行了。
📌 免责:本课为技术科普,所有数据与数字均来自公开渠道的实测,仅用于教学;不构成任何投资建议;投资有风险,盈亏自负。
这一节你完成了第一次真刀真枪的数据体检:六项检查,揪出三个「病灶」,并且给每个都找到了历史真相——17 天是春节,+9.39% 是 6·24 行情,721 个零是指数回溯段。你已经会做「给可疑值找解释」这件最专业的小事了。
数据买回来了、也体检干净了——是时候看看它长什么样了。
下一节,我们把这 5000 多根 K 线画出来:蜡烛图、均线、成交量,一张图看懂二十年。同时我也会提前打好一针疫苗:图是用来理解数据的,不是用来「看图找买点」的——这两者的区别,恰恰是科学和玄学的分界线。
🔎 来源与核验· 3 条,点开核对
