4. 数据质量评估指标:完整性、准确性、一致性、及时性、唯一性

好,咱们进入正题。数据清洗完了,怎么知道洗得干不干净?

你不能光凭感觉说「嗯,这数据看起来不错」。量化交易里,一个错误的数据点,可能让你亏掉六位数。我见过太多人,花了一周写清洗脚本,最后连个评估指标都没有,直接拿去跑策略——结果可想而知。

所以,今天咱们聊聊五个核心指标:完整性、准确性、一致性、及时性、唯一性。说白了,就是给数据做个「体检报告」。

核心观点: 没有评估,就没有控制。你没法改进你无法衡量的东西。

数据质量评估指标 完整性 准确性 一致性 及时性 唯一性 缺失率 误差范围 跨源比对 延迟统计 重复率 字段空值 价格校验 时间对齐 时间戳检查 主键检查

4.1 完整性(Completeness)

完整性,说白了就是「该有的数据有没有」。Tick 数据里,每个时间戳都应该有对应的价格、成交量、买卖盘口。如果某个字段是空的,那就是不完整。

定义: 数据集中非空值记录占总记录数的比例。

计算公式:

完整性 = (1 - 缺失记录数 / 总记录数) × 100%

我在项目中遇到过: 有一次处理某交易所的 Level 2 数据,发现下午 2:30 到 2:45 之间,卖一价字段全部为空。后来排查发现是交易所网关的一个 bug。如果没有完整性检查,策略在那段时间会直接崩掉。

实战建议: 我个人习惯按字段分别统计完整性。比如价格字段完整性必须 ≥ 99.99%,盘口字段可以稍微放宽到 99.9%。别一刀切。

代码示例:

def check_completeness(df, field='last_price'):
    total = len(df)
    missing = df[field].isna().sum()
    completeness = (1 - missing / total) * 100
    print(f"{field} 完整性: {completeness:.4f}%")
    return completeness

4.2 准确性(Accuracy)

准确性衡量的是「数据对不对」。你想想看,数据是完整的,但价格是错的,那比缺失更可怕——它会让你做出错误的交易决策。

定义: 数据值与真实值或公认标准值的一致程度。

计算方法:

  • 价格校验: 检查价格是否在合理范围内(比如 A 股价格不能为负,不能超过 1000 元)
  • 涨跌幅校验: 单笔 Tick 价格变动是否超过涨跌停板限制
  • 买卖价差校验: 买一价必须 ≤ 卖一价,否则数据肯定有问题

⚠️ 注意: 我曾经遇到过一个坑——某数据源把「昨收价」和「当前价」搞反了。准确性检查时,价格范围都正常,但算出来的涨跌幅全是反的。所以一定要做交叉校验。

代码示例:

def check_accuracy(df, price_field='last_price', lower=0.01, upper=1000):
    errors = df[(df[price_field] < lower) | (df[price_field] > upper)]
    accuracy = (1 - len(errors) / len(df)) * 100
    print(f"价格准确性: {accuracy:.4f}%")
    return accuracy

4.3 一致性(Consistency)

一致性,就是「不同地方的数据能不能对上」。Tick 数据经常有多个数据源,比如交易所直连、第三方数据商、自己录的数据。如果它们对不上,你信谁?

定义: 同一数据在不同系统、不同时间、不同表示形式下保持一致的程度。

检查维度:

检查类型 说明 示例
跨源一致性 不同数据源同一时刻的数据是否一致 数据源A vs 数据源B 的 last_price
时间一致性 时间戳是否严格递增 t1 < t2 < t3 ...
逻辑一致性 买卖盘口逻辑是否自洽 bid_price ≤ ask_price

代码示例:

def check_time_consistency(df, time_field='timestamp'):
    # 检查时间戳是否严格递增
    diffs = df[time_field].diff().dropna()
    inconsistent = (diffs <= 0).sum()
    consistency = (1 - inconsistent / len(diffs)) * 100
    print(f"时间一致性: {consistency:.4f}%")
    return consistency

4.4 及时性(Timeliness)

及时性,衡量的是「数据来得够不够快」。做高频交易的,数据晚到 1 毫秒,行情就变了。做日频的,晚到 1 分钟可能还能接受。所以这个指标跟你的策略频率强相关。

定义: 数据从产生到可被使用的时间延迟。

计算方法:

  • 延迟统计: 计算每个 Tick 的接收时间戳 vs 交易所时间戳的差值
  • 阈值判断: 设定一个可接受的最大延迟(比如 100ms),统计超时比例

实战技巧: 我建议你画一个延迟分布图。如果大部分数据延迟在 10ms 以内,但偶尔有 500ms 的尖峰,那可能是网络抖动。这时候要及时性指标要按分位数来算,别被平均值骗了。

代码示例:

def check_timeliness(df, threshold_ms=100):
    delays = df['receive_time'] - df['exchange_time']
    overdue = (delays > threshold_ms).sum()
    timeliness = (1 - overdue / len(df)) * 100
    print(f"及时性 (阈值{threshold_ms}ms): {timeliness:.4f}%")
    return timeliness

4.5 唯一性(Uniqueness)

唯一性,就是「有没有重复数据」。Tick 数据里,同一个时间戳、同一个价格、同一个成交量,如果出现两次,那就是重复。重复数据会扭曲你的统计指标,比如把成交量算成两倍。

定义: 数据集中不存在重复记录的程度。

计算公式:

唯一性 = (1 - 重复记录数 / 总记录数) × 100%

我在项目中遇到过: 有一次做回测,发现某天的成交量异常高。查了半天,原来是数据商在某个时间段重复推送了同一批 Tick。唯一性检查直接帮我揪出了这个问题。

⚠️ 注意: 唯一性检查要基于「业务主键」来判断。对于 Tick 数据,主键通常是 (时间戳 + 股票代码 + 价格 + 成交量)。别只看时间戳,因为同一毫秒内可能有多个不同的成交。

代码示例:

def check_uniqueness(df, subset=['timestamp', 'symbol', 'price', 'volume']):
    total = len(df)
    duplicates = df.duplicated(subset=subset).sum()
    uniqueness = (1 - duplicates / total) * 100
    print(f"唯一性: {uniqueness:.4f}%")
    return uniqueness

4.6 综合评估:如何给数据打分?

五个指标都算出来了,怎么综合判断?我个人习惯用加权平均法。

综合质量评分公式:

Q = w1 × C1 + w2 × C2 + w3 × C3 + w4 × C4 + w5 × C5

其中:
C1 = 完整性
C2 = 准确性
C3 = 一致性
C4 = 及时性
C5 = 唯一性
w1~w5 为权重,总和为 1

权重建议(高频场景):

指标 权重 说明
完整性0.25缺数据就没法交易
准确性0.30错数据比缺数据更致命
一致性0.20多源数据必须对齐
及时性0.15高频交易对延迟敏感
唯一性0.10重复数据影响统计

我的经验: 如果综合评分低于 95 分,我建议你重新审视清洗流程。低于 90 分,直接弃用这批数据,别犹豫。亏钱比重新清洗更痛。

好了,这五个指标就是你的数据质量「体检表」。每次清洗完数据,跑一遍这五个函数,心里就有底了。别偷懒,养成习惯。


公众号:蓝海资料掘金营,微信deep3321