2. Pandas基础回顾:DataFrame与Series核心操作、索引与切片、缺失值处理基础、时间序列索引
各位同学,咱们直接进入正题。做量化投研,数据清洗是逃不掉的一关。而Pandas,就是咱们手里最顺手的工具。今天这一章,我带你快速过一遍Pandas的核心操作,重点放在你写策略、做回测时真正会用到的那些东西上。
本章核心脉络:从数据结构(Series/DataFrame)→ 索引切片 → 缺失值处理 → 时间序列索引。这四个环节,是量化数据清洗的基石。
2.1 数据结构:Series 与 DataFrame
说白了,Series就是一列带标签的数据,DataFrame就是多列拼起来的表格。我刚开始用Pandas时,总把DataFrame当成Excel表格来理解,其实也差不多,但Pandas的灵活性强太多了。
import pandas as pd
import numpy as np
# 创建一个Series
s = pd.Series([100, 102, 101, 105], index=['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'])
print(s)
# 创建一个DataFrame
df = pd.DataFrame({
'open': [100, 102, 101, 105],
'high': [103, 104, 103, 107],
'low': [99, 101, 100, 104],
'close':[102, 101, 105, 106],
'volume':[10000, 12000, 11000, 15000]
}, index=pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04']))
print(df.head())
我的习惯:拿到数据后,第一件事就是 df.info() 和 df.describe()。看一眼数据类型和基本统计量,心里就有底了。千万别上来就做复杂操作,先摸清数据底细。
2.2 索引与切片:loc、iloc 与布尔索引
索引切片是高频操作,我几乎每天都在用。这里有个坑——loc 和 iloc 的区别,很多人一开始会搞混。
- loc:基于标签(label)索引。比如
df.loc['2024-01-01']取的是标签为 '2024-01-01' 的行。 - iloc:基于整数位置(position)索引。比如
df.iloc[0]取的是第0行。 - 布尔索引:用条件筛选。比如
df[df['close'] > 103]。
# loc 示例
print(df.loc['2024-01-02':'2024-01-04', ['open', 'close']])
# iloc 示例
print(df.iloc[0:2, 0:3])
# 布尔索引:筛选出收盘价大于103的交易日
print(df[df['close'] > 103])
我曾经踩过的坑:用 df['2024-01-01'] 直接索引,结果报错。原因是索引是 DatetimeIndex 类型,需要用 df.loc['2024-01-01'] 才行。记住:[] 默认对列名操作,对行操作要用 loc 或 iloc。
2.3 缺失值处理基础
真实数据里,缺失值太常见了。交易所数据偶尔会断点,财务数据可能某期没更新。处理缺失值,我一般分三步走:
- 发现缺失:
df.isna().sum()快速定位哪些列有缺失。 - 判断原因:是数据本身缺失,还是合并时产生的?
- 选择策略:填充(fillna)还是删除(dropna)?
# 构造一个有缺失值的DataFrame
df_missing = pd.DataFrame({
'close': [102, np.nan, 105, 106],
'volume': [10000, 12000, np.nan, 15000]
}, index=pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04']))
print(df_missing.isna().sum())
# 填充:用前一个值填充(适合时间序列)
df_missing['close'].fillna(method='ffill', inplace=True)
# 删除:如果某行缺失太多,直接删掉
df_missing.dropna(thresh=2, inplace=True) # 至少保留2个非空值
print(df_missing)
我个人建议:对于时间序列数据,尽量用 ffill(前向填充)或 interpolate(插值),别轻易删数据。删掉一行,可能就丢掉了一个交易日的信号,回测结果会失真。
2.4 时间序列索引
量化数据最核心的就是时间。Pandas 的 DatetimeIndex 让时间操作变得非常优雅。你想想看,如果没有时间索引,你要手动算日期偏移、重采样,那得多痛苦。
| 操作 | 说明 | 示例 |
|---|---|---|
| 创建 DatetimeIndex | 将字符串列转为时间索引 | pd.to_datetime(df['date']) |
| 设置索引 | 将时间列设为行索引 | df.set_index('date', inplace=True) |
| 时间切片 | 按日期范围筛选 | df.loc['2024-01':'2024-03'] |
| 重采样 | 将日频数据转为周/月频 | df.resample('W').mean() |
| 滚动计算 | 计算移动平均等 | df['close'].rolling(5).mean() |
# 重采样示例:将日线数据转为周线
df_weekly = df.resample('W').agg({
'open': 'first',
'high': 'max',
'low': 'min',
'close': 'last',
'volume': 'sum'
})
print(df_weekly)
# 滚动计算:5日移动平均
df['ma5'] = df['close'].rolling(window=5).mean()
print(df[['close', 'ma5']])
重点提醒:时间序列索引一定要确保是 DatetimeIndex 类型,否则很多时间操作会报错。我习惯在数据加载后,第一时间用 pd.to_datetime() 转换,然后 set_index()。这一步做好了,后面所有操作都顺滑。
嗯,以上就是Pandas基础回顾的核心内容。数据结构、索引切片、缺失值处理、时间序列索引——这四个点你掌握扎实了,后面做数据清洗和特征工程就会轻松很多。记住,量化投研的数据处理,80%的时间都花在清洗和整理上,基础打牢,事半功倍。