DataFrame 能创建成功,为什么不代表数据已经可以放心计算?

DataFrame:表格化处理

约 11 分钟5 道自测更新于 2026-10-27

一句话记住先定义每行含义、键、类型、单位和缺失规则,再做筛选、分组、变形和连接;表格“长得规整”不是质量证明。

01学完你能做到

说明 DataFrame 中每行和每列的业务含义;正确使用筛选、分组、变形和连接;识别类型混杂、重复键、标签错位和缺失记录造成的静默错误。

02这课解决什么问题

DataFrame 能创建成功,为什么不代表数据已经可以放心计算?金融数据最容易出错的地方,是一行代表什么没有说清、连接后行数悄悄变多,或缺失被当成正常数字。

03DataFrame、列类型与索引

DataFrame 是带行列标签的二维表;Series 是一维带标签数据结构;Index 是行标签。Index 可以重复,不能直接当数据库唯一键。

pandas 一列通常有一个 dtype,但 object 列内部可能混有整数和字符串。把表创建出来,不等于价格已经是有效数值。金融字段还需要业务约束:证券代码保留字符串和市场语义,成交量标明股或手,价格注明原始或复权口径,缺失、零值和不可用状态分开表示。

先写“一行的含义”。例如日行情长表可以约定一行等于“某来源、某价格口径下,一只证券在一个交易日的一个版本”。如果有多个来源或修订版本,仅代码加日期可能不唯一。

04四个常用动作

筛选与分组

筛选回答“哪些记录符合条件”;groupby 回答“哪些记录应分别计算”。算收益前先检查证券和日期键,再按证券分组、按时间排序。pct_change 比较相邻观测行,不会自动确认两天是否为相邻交易日。

结果 0.02 表示 2%,不是 0.02%。计算时保留精度,展示时再四舍五入;过早舍入可能改变阈值筛选。

长表与宽表

长表适合保留证券、日期、来源和状态;宽表适合同一时点的多证券比较。pivot 要求索引和列的组合唯一;重复键应先调查来源、修订或输入错误,不能用平均值把冲突隐藏掉。melt 能把宽表变成长表,但不会自动恢复已经丢掉的来源和版本信息。

连接与标签对齐

merge 可以按普通列或索引连接。连接主表时,若行情表多行对应主表一行,可用 validate="many_to_one" 检查。右表重复键会放大行数,成交量和计数可能因此翻倍。

Series 运算按标签对齐,而不是按屏幕行位置。例如左表 A=1、B=2,右表顺序是 B=10、A=20,相加结果仍是 A=21、B=12。pandas 的 merge 对两边空键的处理也要单独确认,不能直接套用其他数据库的直觉。

05代码:先校验再计算

import pandas as pd

df = pd.DataFrame({
    "date": pd.to_datetime(["2026-10-21", "2026-10-22", "2026-10-23"] * 2),
    "instrument_id": ["DEMO_A"] * 3 + ["DEMO_B"] * 3,
    "close": [10.0, 10.2, 9.9, 12.0, 12.6, 12.5],
    "volume": [1000, 1500, 800, 2000, 2600, 1800],
})
keys = ["instrument_id", "date"]
assert not df.duplicated(keys).any()
for col in ["close", "volume"]:
    df[col] = pd.to_numeric(df[col], errors="raise")
assert df["close"].gt(0).all() and df["volume"].ge(0).all()
df = df.sort_values(keys)
df["ret"] = df.groupby("instrument_id")["close"].pct_change(fill_method=None)

master = pd.DataFrame({"instrument_id": ["DEMO_A", "DEMO_B"], "currency": ["CNY", "CNY"]})
joined = df.merge(master, on="instrument_id", how="left",
                  validate="many_to_one", indicator=True)
assert len(joined) == len(df)
print(joined)

教学代码用 assert 表达快速检查;生产服务应使用显式校验、错误记录和告警,因为某些运行选项可能禁用断言。

06四类需要重点审查的错误

  1. 行数悄悄变多:连接前后记录数、匹配率和键唯一性都要记录。
  2. 用今天的主数据解释过去:历史分类、上市状态和证券名称可能需要生效区间;时间可用性不能被忽略。
  3. 缺失记录被跳过:跨过多个交易日的两条价格仍会产生数字,但不能无条件叫作单日收益。
  4. 接口类型不稳定:数字、空字符串和不同时间格式混在一起,会让下游解析不稳定。应明确 schema、缺失约定、单位和版本兼容规则。

07工具选择的基本判断

工具常见特点需要验证
pandas单机内存处理,标签对齐语义重要内存峰值、类型、索引和耗时
Polars表达式和惰性执行,部分场景可流式处理操作覆盖、转换成本和实际性能
Spark DataFrame分区执行,可进行分布式计算数据规模、shuffle、资源和运维成本

不要只凭“数据有多少 GB”决定技术栈。先减少无用列、过滤日期、检查类型和分区读取,再用真实查询压测。

08延伸阅读

09一分钟讲给别人

试着用自己的话讲一遍DataFrame 帮我们把同一种操作重复执行,但计算前要先说明每行含义和键。算收益先分组排序,还要查缺失日期;连接要检查唯一性和行数;数字类型、单位和价格口径都要确认。

想一想

5 道自测

先在心里答一遍,再展开对照。能说清理由,比答对数字更重要。

  1. 01为什么 Index 不能直接当数据库唯一键?

  2. 02`pct_change` 为什么不能自动证明结果是“单日收益”?

  3. 03`merge` 后行数变多,最常见的原因是什么?

  4. 04为什么不能用平均值直接消除重复键?

  5. 05Series 运算按什么规则对齐?

已看 0/5 题

练动手练习

任务:在样本中复制 DEMO_A 的第二天记录,先预测哪个检查会失败,再运行。然后把一个 close 改成“暂停”,说明错误信息至少应包含字段、记录标识、原始值和预期类型。

完成这一课

完成这一课

读完讲义、看完自测答案,这一课就算学完了。

  • 读完讲义
  • 看完全部自测

本课为投资者教育内容,案例数字均为示意,不构成任何投资建议,也不承诺收益。规则和费率会变,实际操作前请以交易所、监管机构和产品的最新公告为准。