📎 配套代码:
第01讲_导论.py
📊 配套数据:data/quote/—— 交易数据(沪深300 × 2024 年以来,仓库自带,开箱即跑)
🎬 开场:先看一段”没有任何问题”的代码
你让 AI 写一段代码:算每只股票的日收益率。它给你这个:
df = pd.read_csv("stocks.csv") # 从数据库导出的行情,每行 = 某股票某天 df["ret"] = df.groupby("code")["close"].pct_change() print(df["ret"].describe())
跑起来了。不报错,不警告,describe() 打出来均值 0.0004、标准差 0.021——看着完全正常。
但是,它是错的。
问题在于:数据库导出的数据每只股票内部不是按日期排的。而 groupby 保持组内的原始行顺序,pct_change 就老老实实按这个乱序算了差分——用 3 月 15 日的收盘价除以 8 月 2 日的,再减一。
整列收益率是垃圾。但它长得和真的一模一样:数量级对、有正有负、分布看着也合理。你唯一能发现它的方式,是你本来就知道”groupby 保持组内原序”这件事。
正确的写法只多一步:
df = df.sort_values(["code", "date"]) # ← 就这一行 df["ret"] = df.groupby("code")["close"].pct_change()
IMPORTANT: 🔑 这就是这门课存在的理由
不是”AI 写不好代码,所以你得自己写”。AI 写得挺好。
是“AI 写的代码你得能验收”——而在数据处理里,错误不会喊出来。
🎬 为什么量化里的错特别危险:它不报错,只让结果变好看
写网站,bug 会自己喊:页面崩了、按钮点不动、控制台一片红。错误是有声音的。
数据分析不是。上面那段代码的四类近亲,你大概率都会遇到:
| 写法 | 症状 | 真实后果 |
|---|---|---|
groupby 前没排序 |
无 | 组内按乱序算差分,整列是垃圾 |
shift(-1) 写成 shift(1)
|
无 | 用了未来数据,回测曲线漂亮到不真实 |
pct_change() 不关 fill_method
|
无 | 缺失值被前向填充,凭空造出没有的数据 |
| 财务数据按报告期而非公告日对齐 | 无 | 用了三个月后才公布的信息 |
这四个都不报错。 它们的唯一症状是:结果变好看了。
而”结果变好看”恰恰是你最不会去质疑的时候。这就是数据工作的特殊之处——你的怀疑心必须由知识提供,不能指望报错。
NOTE: 🏦 这不是编出来的教学案例
上表第一行和第三行,是这套课程体系在写 FI(因子投资)和 ER(预期收益)时真踩到、然后被数字揪出来的。所以那两门课的代码里至今留着两条注释:「pct_change前必须先排序,否则跨公司串行」「必须显式关掉fill_method,否则前向填充造假数据」。
🎬 那 vibe coding 到底改变了什么
改变了很多,但没改变最关键的那一环。
真实的 vibe coding 工作流不是「提需求 → 拿代码 → 用」,而是:
提需求 → 拿代码 → 【看一眼,判断对不对】 → 不对,再说清楚
↑
这一步没法外包
- 看不懂
df.groupby(level=0).apply(...)在按什么分组 → 你只能信 - 看不出
df[df.a > 0]["b"] = 1这句赋值根本不生效(第 07 讲)→ 你只能信 - 不知道
merge完行数悄悄少了 30% → 你只能信
在量化里,盲信的代价是真金白银。
反过来更实在:懂 pandas 的人用 AI 效率高得多。因为你能直接说「用 transform 别用 apply」「这里加 observed=True」「先 sort_values 再 groupby」。约束给得越准,AI 给的东西越对。不懂的人只能说「帮我算个因子」,然后收到一段无法验收的代码。
还有一层更难的:AI 只回答你问的问题。
你问「怎么加一列」,它给你 df["x"] = ...,不会告诉你「你在循环里这么加会碎成 30 个内存块」(第 06 讲)。它不会主动提醒你不知道的事——而”不知道自己不知道什么”,正是这门课要解决的。
IMPORTANT: 🔑
AI 解决的是「知道该问什么之后,怎么做」。
这门课要解决的是前半段:该问什么。
做个跨学科的类比,如果要生成下面的图片,你的提示词要怎么写?如果没有相关专业领域的知识是写不出来的,从而也画不出来。因此,学习pandas就是让我们能在vibe coding时代,知道该设计怎么的提示词画出以下的专业图。

生成上图的中英文提示词: 请生成一张用于论文的肿瘤免疫微环境机制示意图。 以肿瘤微环境作为中心场景,展示纳米治疗平台进入肿瘤组织后,对免疫微环境产生调控作用,包括诱导巨噬细胞由 M2 向 M1 极化、促进树突细胞激活、增强 CD8+ T 细胞浸润,并最终促进肿瘤细胞杀伤。 请采用中心聚焦式构图,以肿瘤组织和免疫细胞互作为主画面,在周围加入局部放大视图,用于展示不同免疫细胞之间的信号传递、激活和抑制关系。 整体风格要求简洁、专业、适合论文发表,呈现高质量生物医学机制图风格,图面干净,结构清晰,逻辑明确。 请使用明亮背景,以蓝绿色为主色,橙色和红色仅用于强调免疫激活和肿瘤杀伤事件。 请使用清晰箭头以及激活/抑制关系符号来表示不同细胞之间的调控关系。 Create a publication-ready scientific mechanism schematic of the tumor immune microenvironment. Use the tumor microenvironment as the central scene, showing how a nanotherapeutic platform regulates immune responses after entering tumor tissue, including macrophage polarization from M2 to M1, dendritic cell activation, enhanced CD8+ T cell infiltration, and ultimately tumor cell killing. Use a center-focused composition, with tumor tissue and immune cell interactions as the main visual scene, and add surrounding zoom-in views to illustrate signaling, activation, and inhibition relationships among different immune cells. Use a clean, professional, high-quality biomedical mechanism illustration style, with a tidy appearance, clear structure, and strong logical readability. Use a bright background, with blue-green as the dominant palette, and orange or red only to highlight immune activation and tumor-killing events. Use clear arrows and activation/inhibition symbols to indicate regulatory relationships among cells.
一、💡 pandas 是什么:数据分析要干的活,它全包了
假设你要回答一个问题:“过去三年,哪些行业的股票在财报发布后表现更好?”
从零到答案,你必须依次做这些事:
一次分析要干的 11 件事
| # | 要干的活 | 具体是什么 | pandas 里怎么做 | 本课 |
|---|---|---|---|---|
| 1 | 读进来 | 行情在 CSV、财报在 Excel、行业分类在数据库 |
read_csv / read_excel / read_sql / read_parquet
|
08 |
| 2 | 先看一眼 | 多少行?什么类型?有没有缺失?分布如何? |
head / info / describe / value_counts
|
08 |
| 3 | 清洗 | 日期是字符串、价格有负数、代码有空格、有重复行 |
astype / to_datetime / str.strip / drop_duplicates
|
09-10 |
| 4 | 处理缺失 | 停牌没数据、新股上市前是空的 |
isna / fillna / dropna / ffill
|
09 |
| 5 | 筛选 | 只要主板、只要 2022 年后、只要市值前 500 | 布尔索引 / query / loc
|
07 |
| 6 | 派生新列 | 算收益率、算均线、算财报发布后第 N 天 | 整列运算 / rolling / shift
|
06-07 |
| 7 | 合并多表 | 行情表 + 财报表 + 行业表,按代码和日期对上 |
merge / join / concat
|
13 |
| 8 | 重塑 | 长表变宽表(行=日期、列=股票),或反过来 |
pivot / melt / stack / unstack
|
14 |
| 9 | 分组聚合 | 按行业、按年份,算平均收益、算数量 | groupby().agg() |
15-17 |
| 10 | 时序处理 | 日频转月频、算 20 日滚动波动、对齐交易日 |
resample / rolling / asfreq
|
18-19 |
| 11 | 出结果 | 排序取 top、画图、存成文件给别人 |
sort_values / plot / to_csv
|
20 |
这 11 件事,pandas 全都能做,而且是用同一套数据结构、同一套语法做的。
这就是”瑞士军刀”的意思——不是它某一项特别强,而是整条链路你不用换工具。
换个工具会怎样
| 工具 | 能干上面几件 | 卡在哪 |
|---|---|---|
| Excel | 1-6、9、11 | 几十万行就卡死;多表关联靠 VLOOKUP 易错;重塑和时序很吃力;改一次要重做一遍 |
| SQL | 1、5、7、9 | 擅长筛选/关联/聚合,但时序滚动窗口、重塑、画图都很别扭 |
| 纯 Python | 都能做 | 每件事都要自己写循环,代码量十倍,且容易出错 |
| numpy | 部分 | 只有数字,没有列名、不能混类型、缺失值难处理——真实数据一进来就卡住 |
| pandas | ✅ 全部 | — |
IMPORTANT: 🔑 pandas 的定位
它不是”更好的 Excel”,也不是”Python 版的 SQL”。
它是唯一能把上面 11 件事从头到尾串起来的工具——而且串起来的过程是代码,意味着可复现、可版本管理、可以让 AI 帮你写。
那 numpy 是什么关系
pandas 底层就是 numpy。numpy 提供”一块连续内存 + 整块运算”的能力,pandas 在它之上加了三样真实数据必需的东西:
- 列名和行索引(numpy 只有位置,pandas 能按标签取、按标签自动对齐)
- 每列可以不同类型(numpy 一个数组只能一种类型,而真实数据有数字有文本有日期)
- 缺失值支持(真实数据永远有缺失)
所以这门课先花三讲打 numpy 地基(第 02–04 讲),再上 pandas——你会发现 pandas 的很多行为,根子都在 numpy 那一层。
🎮 随堂快练
QUESTION: 上面 11 件事里,你觉得哪几件是 Excel 做起来最痛苦的?为什么?
TIP: 👉 参考
最痛苦的通常是 7 合并多表、8 重塑、10 时序处理:
- 合并:VLOOKUP 只能单键匹配,而金融数据常要”代码 + 日期”双键对齐;且匹配不上时静默出错。
- 重塑:长宽表互转在 Excel 里要靠数据透视表手工拖,换个维度就得重做。
- 时序:20 日滚动波动率要拖公式;日频转月频要手工分组。
更根本的问题是 11 件事在 Excel 里是”一次性操作”——改了源数据要重做一遍,而且没人知道你当初点了哪些按钮。代码是可复现的,鼠标操作不是。
二、🧠 向量化思维
什么是向量化思维
把”对每一行做什么”改成”对整列做什么”。
如果暂时对这个向量化思维不理解也没有关系,可以先跳过。
同一个任务——「给收益率打标签,涨的标”涨”,其余标”跌”」——两种想法:
labels = [] # 循环思维:描述"怎么一步步做" for v in ret: # 我来遍历 if v > 0: # 我来判断 labels.append("涨") # 我来收集 else: labels.append("跌") labels = np.where(ret > 0, "涨", "跌") # 向量化思维:描述"我要什么"
区别不在代码长短,在谁来做遍历这件事:
| 循环思维 | 向量化思维 | |
|---|---|---|
| 遍历 | 你写 | 交给库 |
| 你说的话 | “取第一个,判断,放进去;取第二个……” | “凡是大于 0 的位置放’涨’,其余放’跌’” |
| 关注点 | 过程 | 结果的形状 |
ret > 0 这一步是关键:它一次性对整列产生一个布尔数组 [True, False, True, ...],np.where 再一次性按这个数组选值。整个过程你没有碰过任何单个元素。
IMPORTANT: 🔑 向量化思维的核心动作
遇到”要对数据做点什么”时,先问自己:
“我能不能不提单个元素,只描述整列应该变成什么样?”
能,就是向量化写法。
pandas 是怎么做到向量化的
你写 ret > 0,pandas 内部发生了什么?
你写: ret > 0
│
├─ ① ret 内部是一整块连续内存(一列 float64 挨着放)
│
├─ ② 把"逐个比较"这件事交给底层的 C 代码
│ C 循环没有 Python 解释器的开销,还能用 CPU 的批量指令
│
└─ ③ 返回一整个布尔数组 [True, False, True, ...]
——同样是一整块内存
对比你自己写循环:
| 你的 Python 循环 | pandas 向量化 | |
|---|---|---|
| 循环在哪 | Python 里,每轮都要解释执行 | C 里,编译好的机器码 |
| 每个元素 | 要包装成 Python 对象再比较 | 直接在内存上比较原始数值 |
| 中间结果 | 一个 Python list,装着一堆对象 | 一块连续的布尔数组 |
NOTE: 这就是为什么”整列一次性”是可能的
pandas 的一列在内存里是连续的一整块(第 06 讲会看到 DataFrame 内部就是按列存的)。既然是一整块,就可以整块交给 C 去处理——这是向量化能成立的物理前提。而 Python 的
list是一堆散落的对象指针,没法整块处理,只能一个个来。
所以”向量化”不是一个技巧,是一种由数据结构决定的能力:数据是整块的 → 才能整块地算 → 你才能整块地想。
🎮 随堂快练
QUESTION: 把一列价格
p里所有负数(脏数据)替换成 0。写出向量化写法,并说明你为什么选它。
TIP: 👉 答案
三种都对:p = np.where(p < 0, 0, p) # 通用 p[p < 0] = 0 # 就地改 p = p.clip(lower=0) # ✅ 最好选
clip——它把意图(下限截断)直接说出来了,读的人不用去想”这个 where 在干嘛”。这正是理由①:表达意图,不是步骤。⚠️ 顺带一问:如果
p里有 NaN 会怎样?p < 0对 NaN 是False,所以 NaN 会原样保留(不会变成 0)。三种写法都一样。这是好事还是坏事,取决于你的需求——但你得知道它发生了。
三、🗺️ 后面 21 讲讲什么
全课 22 讲,分四段。每一讲配一份可运行的代码和仓库自带的样本数据,课件里的每个数字都来自真实运行。
第 02–04 讲 numpy 地基:取数的三种方式
pandas 的 iloc、loc、布尔索引,根子都在这三讲。先在原生容器上把手感练出来,后面上 pandas 只是换个外壳。
| 讲 | 讲什么 | 具体解决什么 |
|---|---|---|
| 02 | 按位置取数:元组、列表与数组 | 切片、步长、多维索引。取”最近 250 个交易日””每只股票掐掉上市前 60 天” |
| 03 | 按标签取数:字典与结构化数组 | 排序会重排位置,close[0] 指的股票会变。用名字指向数据,重排不受影响 |
| 04 | 按条件取数:布尔掩码 | 你不知道是哪些,只知道它们满足什么。条件先变成一串 True/False,再拿去取 |
第 05–07 讲 pandas 的两个结构
| 讲 | 讲什么 | 具体解决什么 |
|---|---|---|
| 05 | Series:带标签的一维数据 | 数组会算不会认,字典会认不会算。Series 把两样合成一个,还带自动对齐 |
| 06 | DataFrame:带行列标签的表格 | 多字段、多类型的真实表格。建表、取数、增删改、筛选、排序 |
| 07 | apply:把自己的函数用到数据上 | 内置函数覆盖不到的业务逻辑。也讲什么时候不该用它——它是最容易被滥用的操作 |
第 08–19 讲 数据处理:一条链上的十二件事
这十二讲是全课的主体,顺序就是真实分析的顺序:读进来 → 清洗 → 拼接 → 变形 → 分组 → 时序。
| 讲 | 讲什么 | 具体解决什么 |
|---|---|---|
| 08 | 数据加载与存储 | CSV / Excel / SQLite / Parquet。同一个文件同一个函数,加两个参数省 697 倍内存 |
| 09 | 缺失数据与排序 | 两个互补的条件加起来对不上——NaN 从两个桶里都漏了出去。以及排序、rank 与并列处理 |
| 10 | 数据转换与字符串处理 | 两张表按代码合并,一条都没对上:000001.SZ 和 000001 是两个值 |
| 11 | Categorical 分类数据 | 分档标签转成字符串后,排序变成”中、大、小、最大、最小”。以及分类列不能做算术 |
| 12 | MultiIndex 层次索引 | 时序视角和截面视角。平表上每次全表扫描,层次索引上快 30~73 倍 |
| 13 | 合并连接 |
how="left" 合并之后行数变多了。validate= 怎么把假设写进代码 |
| 14 | 重塑与透视 | 长表和宽表的取舍。同一个截面 z-score,宽表比长表快 55 倍 |
| 15 | 分组与聚合 |
groupby().agg():17 万行压成 300 行的股票画像表 |
| 16 | transform 与组内变换 | 行业中性化 agg 给不了——它把组的统计量广播回每一行,形状不变 |
| 17 | 透视表与交叉表 | 只看一个维度会骗你:动量单调递减的结论,加上市值维度就不成立了 |
| 18 | 时间序列(上):时间类型与索引 | 字符串日期能走多远,以及转换时那些不报错的坑 |
| 19 | 时间序列(下):重采样与移动窗口 | 面板上直接 rolling,茅台的第一条均线混进了五粮液的价格——5700 行是错的 |
第 20–22 讲 三个综合案例
前十九讲每讲解决一个局部问题,这三讲把它们串成完整流程。练的是数据处理,不是投资判断——因子有没有效是别的课的事。
三讲都按同一个结构走:要算什么 → 要用什么数据 → 设计思路 → 伪代码 → 逐段实现 → 复盘。
| 讲 | 案例 | 走的是哪条链 |
|---|---|---|
| 20 | 单因子测试流水线 | 原始行情 → 去极值 → 标准化 → 中性化 → IC 与分档收益 |
| 21 | 财务因子与时间对齐 | 季频财报 → 按公告日贴到日频(merge_asof)→ 量化”按报告期对齐”错在哪 |
| 22 | 行业轮动策略完整回测 | 日线 → 月频 → 信号 → 权重 → 净值 → 绩效与换手成本 |