3. Pandas时间序列核心工具
在金融时间序列清洗中,时间对象不是简单的字符串,而是承载频率、时区、交易日历与对齐规则的“结构化坐标”。Pandas 提供了五个核心时间工具:Timestamp(单个时间点)、DatetimeIndex(时间点索引)、Period(周期区间)、Timedelta(时间差)、DateOffset(日历偏移)。理解它们的定位差异,是后续重采样、对齐与缺失值处理的基础。
一、核心原理:五个工具的分工
可以把它们理解为“点、轴、段、量、规则”五个层次。Timestamp 是标量时间点,类似 Python 的 datetime,但支持纳秒精度和丰富属性;DatetimeIndex 是 Timestamp 的集合,构成 Series/DataFrame 的时间轴;Period 表示一个固定频率的区间(如“2024-03”整月),适合月度、季度财报数据;Timedelta 是精确的物理时长(如 3 天 5 小时),用于加减运算;DateOffset 是“日历规则”偏移,如“下一个月末”“下一个工作日”,会考虑月份长度、节假日等业务语义。
二、方法流程:创建与常用操作
下面按“创建 → 属性 → 运算 → 转换”四步走,覆盖五个工具的高频用法。
import pandas as pd
from pandas.tseries.offsets import BDay, MonthEnd
# 1. Timestamp 创建
ts = pd.Timestamp("2024-03-15 09:30:00")
ts2 = pd.Timestamp(2024, 3, 15, 9, 30)
print(ts.year, ts.month, ts.dayofweek, ts.quarter) # 2024 3 4 1
# 2. DatetimeIndex 创建
idx = pd.date_range("2024-01-01", periods=5, freq="B") # 工作日
idx2 = pd.to_datetime(["2024-01-01", "2024-02-01", "2024-03-01"])
# 3. Period 创建
p = pd.Period("2024-03", freq="M")
print(p.start_time, p.end_time) # 2024-03-01 00:00:00 2024-03-31 23:59:59.999999999
# 4. Timedelta 创建
td = pd.Timedelta(days=3, hours=5)
td2 = pd.Timestamp("2024-03-15") - pd.Timestamp("2024-03-10") # 5 days
# 5. DateOffset 创建
off = pd.DateOffset(months=1)
off_b = BDay(1) # 下一个工作日
off_me = MonthEnd(1) # 下一个月末
# 运算示例
print(ts + td) # 2024-03-18 14:30:00
print(ts + off) # 2024-04-15 09:30:00
print(ts + off_b) # 2024-03-18 09:30:00(跳过周末)
print(ts + off_me) # 2024-03-31 09:30:00
在金融数据中,DatetimeIndex 是清洗的“主键”。通过 df.set_index(pd.to_datetime(df["trade_date"])) 可将字符串日期转为时间索引,随后即可使用 .loc["2024-03"] 切片、.resample("W") 重采样、.asfreq("B") 补齐工作日。
三、案例场景:月度财报与交易日对齐
假设我们有一组月度财报数据,日期为每月最后一天,但实际交易日可能因节假日提前。需要将其对齐到交易日历,并计算相邻报告期的间隔天数。
# 月度财报:Period 转 Timestamp
reports = pd.Series(
[100, 120, 115],
index=pd.period_range("2024-01", periods=3, freq="M")
)
ts_index = reports.index.to_timestamp(how="end") # 转为月末 Timestamp
# 对齐到交易日:若月末非交易日,取前一个工作日
trade_days = pd.date_range("2024-01-01", "2024-03-31", freq="B")
aligned = reports.copy()
aligned.index = ts_index
aligned = aligned.reindex(trade_days, method="ffill")
# 计算报告期间隔
gaps = ts_index.to_series().diff().dropna()
print(gaps) # 29 days, 31 days(闰年2月)
四、误区与复盘
| 误区 | 表现 | 正确做法 |
|---|---|---|
| 用 Timedelta 代替 DateOffset | 1月31日加30天得到3月1日,而非2月末 | 使用 MonthEnd(1) 或 DateOffset(months=1) |
| 忽略时区 | 跨市场数据对齐时出现8小时偏移 | 用 tz_localize 与 tz_convert 统一时区 |
| Period 与 Timestamp 混用 | resample 报错或结果频率错误 | 明确 to_timestamp / to_period 转换方向 |
| date_range 频率误设 | 用 "M" 得到月初而非月末 | 月末用 "ME"(新版)或 MonthEnd |
| 字符串直接比较 | "2024-1-5" 与 "2024-01-05" 排序错乱 | 先 pd.to_datetime 标准化 |
掌握这五个工具后,后续的重采样、滚动窗口、缺失值填充与多表对齐都将有稳固的坐标基础。建议在真实行情与财报数据上反复练习创建、转换与运算,形成对时间语义的直觉。