2. Pandas基础回顾:DataFrame与Series核心操作、索引与切片、缺失值处理基础、时间序列索引

各位同学,咱们直接进入正题。做量化投研,数据清洗是逃不掉的一关。而Pandas,就是咱们手里最顺手的工具。今天这一章,我带你快速过一遍Pandas的核心操作,重点放在你写策略、做回测时真正会用到的那些东西上。

本章核心脉络:从数据结构(Series/DataFrame)→ 索引切片 → 缺失值处理 → 时间序列索引。这四个环节,是量化数据清洗的基石。

Pandas 基础回顾 数据结构 Series / DataFrame 索引与切片 loc / iloc / 布尔索引 缺失值处理 isna / fillna / dropna 时间序列索引 DatetimeIndex / 重采样 量化数据清洗与特征工程

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 与布尔索引

索引切片是高频操作,我几乎每天都在用。这里有个坑——lociloc 的区别,很多人一开始会搞混。

  • 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'] 才行。记住:[] 默认对列名操作,对行操作要用 lociloc

2.3 缺失值处理基础

真实数据里,缺失值太常见了。交易所数据偶尔会断点,财务数据可能某期没更新。处理缺失值,我一般分三步走:

  1. 发现缺失df.isna().sum() 快速定位哪些列有缺失。
  2. 判断原因:是数据本身缺失,还是合并时产生的?
  3. 选择策略:填充(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%的时间都花在清洗和整理上,基础打牢,事半功倍。


专注资料整理