4. 数据探索与概览:DataFrame 基本信息查看、describe() 统计摘要、info() 数据类型检查
在量化策略回测中,原始数据(如日频 OHLCV、分钟级 Tick 数据)通常以 CSV、Parquet 或数据库形式存储。在进入清洗流程之前,必须对 DataFrame 进行系统性探索与概览。本章聚焦三个核心操作:info() 数据类型检查、describe() 统计摘要、以及基本信息查看(shape、columns、head/tail)。
核心原则:先概览后清洗。跳过数据探索直接清洗,容易遗漏缺失值模式、类型错误或异常分布,导致回测结果失真。
4.1 使用 info() 检查数据类型与内存
DataFrame.info() 是数据清洗的第一步,它一次性输出:列名、非空计数、数据类型(dtype)以及内存使用量。对于回测数据,常见问题包括:日期列被解析为 object 而非 datetime、成交量列被读为 float64 而非 int64、缺失值未正确识别。
import pandas as pd
# 加载示例日频数据
df = pd.read_csv('stock_600519_daily.csv')
df.info()
# 输出示例(非实际数据):
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 2520 entries, 0 to 2519
# Data columns (total 7 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 date 2520 non-null object
# 1 open 2520 non-null float64
# 2 high 2520 non-null float64
# 3 low 2520 non-null float64
# 4 close 2518 non-null float64
# 5 volume 2520 non-null int64
# 6 amount 2520 non-null float64
# dtypes: float64(5), int64(1), object(1)
# memory usage: 137.9+ KB
关键检查点:
- 日期列:dtype 应为
datetime64[ns],若为 object 则需用pd.to_datetime()转换。 - 数值列:OHLC 应为 float64,volume/amount 可为 int64 或 float64。若出现 object,说明存在非数字字符(如逗号、空格)。
- 非空计数:若 Non-Null Count 小于总行数,表示存在缺失值,需后续处理。
- 内存占用:大数据集(百万行以上)可考虑优化 dtype(如使用 int32、float32)以降低内存。
4.2 使用 describe() 获取统计摘要
DataFrame.describe() 对数值列自动计算:计数、均值、标准差、最小值、25%/50%/75% 分位数、最大值。对于回测数据,这些统计量能快速暴露异常值、分布偏态或数据范围错误。
# 对数值列生成统计摘要
df.describe()
# 输出示例(非实际数据):
# open high low close volume amount
# count 2520.00 2520.00 2520.00 2518.00 2520.00 2520.00
# mean 168.32 170.15 166.48 168.20 1.25e+07 2.10e+09
# std 12.45 12.78 12.10 12.33 3.20e+06 5.40e+08
# min 120.10 122.30 118.50 119.80 2.10e+06 3.50e+08
# 25% 158.20 160.10 156.80 158.00 9.80e+06 1.65e+09
# 50% 167.50 169.30 165.70 167.30 1.22e+07 2.05e+09
# 75% 177.80 179.60 176.00 177.50 1.50e+07 2.55e+09
# max 210.50 212.00 208.30 209.80 2.80e+07 4.80e+09
异常值警示:
- 若 min 为负数(如开盘价 -1.0),说明数据存在错误或除权除息未复权。
- 若 max 远超 75% 分位数(如 close 最大值为 9999),可能为数据录入错误或极端事件未过滤。
- 若 count 不一致(如 close 只有 2518 行),需定位缺失行。
- 若 std 为 0,说明该列所有值相同,可能是无效列。
4.3 基本信息查看:shape、columns、head/tail
在 info() 和 describe() 之前,快速查看 DataFrame 的轮廓有助于建立整体认知。
| 方法/属性 | 作用 | 回测场景示例 |
|---|---|---|
df.shape |
返回 (行数, 列数) | 确认数据是否覆盖完整回测周期(如 2520 行 ≈ 10 年交易日) |
df.columns |
返回列名列表 | 检查列名是否包含空格、大小写不一致(如 'Close' vs 'close') |
df.head(n) |
查看前 n 行 | 快速确认日期格式、数据起始点、列顺序 |
df.tail(n) |
查看后 n 行 | 确认数据是否包含未来数据或最新交易日 |
df.sample(n) |
随机抽取 n 行 | 检查数据分布是否均匀,避免头部/尾部偏差 |
# 快速轮廓检查
print('Shape:', df.shape) # (2520, 7)
print('Columns:', df.columns.tolist())
print('Head:\n', df.head(3))
print('Tail:\n', df.tail(3))
4.4 数据探索流程总览
以下 SVG 图展示了从原始数据加载到清洗前的标准探索流程,包含三个核心步骤及其输出。
4.5 实战案例:快速诊断数据问题
假设我们加载了一份分钟级股指期货数据,通过三步探索发现以下问题:
- info() 发现:
datetime列为 object,volume列为 float64 但应为 int64。 - describe() 发现:
close最小值 0.01,远低于正常价格,疑似数据错误;volume标准差极大,可能存在异常大单。 - head/tail 发现:数据尾部包含未来日期(超出回测截止日),需截断。
清洗前必做清单:
- ✅ 日期列转换为 datetime64
- ✅ 数值列检查并修正 dtype
- ✅ 标记缺失值位置(行号、列名)
- ✅ 记录异常值阈值(如价格 < 0.1 或 > 均值+5σ)
- ✅ 确认数据时间范围与回测周期一致