4. 数据清洗与预处理实战
一字涨停竞价封单数据看起来只是“某只股票在某天9:15到9:25之间每分钟的封单金额”,但真正拿到原始数据时,往往是一堆难以直接分析的问题集合:有的时间点没有采集到数据,有的分钟被重复推送,有的封单金额突然出现一个明显不合理的跳变,还有不同交易日的时间戳格式不统一。本节的任务不是做统计建模,而是把原始数据整理成一张“干净、对齐、可比”的结构化表,为后续的封单变化率、封单强度、竞价阶段特征分析打好基础。
先明确清洗对象与目标结构
假设我们从行情接口或手工记录中获得的原始竞价封单数据,字段大致包括:交易日期、股票代码、采集时间、封单金额(万元)、封单手数、竞价阶段标记。目标输出是一张按“股票代码 + 交易日期 + 标准时间点”唯一确定一行记录的结构化数据集,时间点统一为9:15至9:25之间的每分钟整点,封单金额为数值型且单位统一为万元。清洗的核心判断标准只有三条:每个标准时间点有且只有一条记录;数值在合理范围内;时间戳能够正确映射到标准时间轴。
下面这张图展示了从原始数据到结构化数据集的整体处理链路,以及三类问题分别在哪一步被处理、处理后的数据流向何处。图中左侧是原始数据中的典型问题,中间是清洗与对齐操作,右侧是最终可用于分析的标准表结构。
时间标准化:先把“时间”变成可比较的键
原始数据中最常见的问题是时间格式不统一。例如同一天的数据里,可能同时出现“9:15”“09:15:00”“2024-06-03 09:15:32”三种写法。如果不先统一,后续按时间排序、按分钟对齐都会出错。处理原则是:只保留“时:分”,统一补零为两位,秒和日期前缀全部截断。例如“2024-06-03 09:15:32”应转换为“09:15”。这里要注意一个细节:9:25之后的集合竞价撮合结果不属于竞价封单变化过程,通常只保留09:15至09:25共11个标准时间点;如果原始数据包含09:25:00之后的记录,应在标准化阶段直接过滤掉。
完成标准化后,用“股票代码 + 交易日期 + 标准时间”作为唯一键。这个键既是去重的依据,也是后续左连接标准时间轴的依据。建议在代码中显式构造标准时间轴,而不是依赖原始数据中出现了哪些时间点,否则缺失的时间点永远不会被补出来。
去重:同一分钟多条记录怎么取舍
重复推送在行情接口中很常见,表现为同一唯一键出现两到三条记录,封单金额可能完全相同,也可能因为推送延迟略有差异。处理策略应区分两种情况:如果金额完全相同,直接保留一条即可;如果金额不同,应保留时间戳最晚的一条,因为它更接近该分钟结束时的真实封单状态。实现上可以按唯一键分组,按原始时间戳排序后取最后一条。需要提醒的是,去重必须在时间标准化之后进行,否则“9:15”和“09:15:00”会被误判为两条不同记录。
缺失补齐:短缺口前向填充,长缺口标记而非硬补
缺失是竞价封单数据中最需要谨慎处理的问题。封单金额在竞价阶段通常变化平缓,短时间缺口(如连续1至2分钟)用前向填充是合理的,即用上一个有效时间点的封单金额填补。但如果是连续较长的缺口,例如9:16至9:20全部缺失,前向填充会人为制造一条“封单不变”的假曲线,误导后续变化率分析。更稳妥的做法是:对连续缺失不超过2个时间点的缺口做前向填充,并在“数据来源标记”字段中标注为“填充”;对更长的缺口保留空值并标注“缺失”,在分析阶段再决定是否剔除该股票当日样本。这样既保证了时间轴完整,又不掩盖数据质量问题。
异常值:先统一单位,再按业务阈值判断
异常值处理不能只依赖统计方法,必须结合业务含义。第一步是单位统一:封单金额字段可能混用“元”和“万元”,例如同一列中出现“8500000”和“850”,前者明显是以元为单位。处理方式是按数量级判断并统一换算为万元,换算后应在日志中记录被换算的记录数。第二步是业务阈值判断:一字涨停的封单金额通常在一个合理区间内,若某条记录相对前后相邻时间点突增或突降超过设定倍数(例如示例中采用5倍作为筛查阈值),应标记为可疑点。对可疑点不建议直接删除,而是先标记,再人工或规则复核;若确认是采集错误,可用相邻时间点的均值替换,并在来源标记中注明“修正”。
形成结构化数据集后的自检
清洗完成后,建议做三项快速自检:第一,检查唯一键是否真的唯一,即按“代码 + 日期 + 时间”分组后每组记录数是否为1;第二,检查每只股票每个交易日是否恰好有11个标准时间点,缺几个、补了几个应能说清楚;第三,抽查2至3只股票的封单金额序列,确认没有出现数量级明显错误的跳变。完成自检后,这份数据就可以直接进入封单变化率、封单强度曲线等分析环节,而不需要在分析代码中反复处理脏数据。
下面给出一份可直接参考的清洗结果记录表结构,用于在实操中登记每只股票当日的清洗情况,便于追溯和复核。
| 字段 | 示例值 | 说明 |
|---|---|---|
| 股票代码 | 600XXX | 统一为6位代码 |
| 交易日期 | 2024-06-03 | 统一为 YYYY-MM-DD |
| 原始记录数 | 14 | 清洗前该股当日记录条数 |
| 去重删除数 | 2 | 重复推送被合并的条数 |
| 填充时间点数 | 1 | 短缺口前向填充的数量 |
| 缺失时间点数 | 0 | 长缺口保留空值的数量 |
| 异常标记数 | 1 | 被标记为可疑的记录数 |
| 最终有效时间点数 | 11 | 应为09:15至09:25共11个 |
这张记录表的价值在于:当后续分析发现某只股票封单曲线异常时,可以快速回查是原始数据缺失、填充过多,还是异常值修正导致,而不是在一堆清洗代码里反复猜测。数据清洗的目标不是让数据“看起来完整”,而是让每一个被填补、被修正、被删除的动作都有据可查,这样形成的结构化数据集才真正可用于一字涨停竞价封单变化的分析。