3. Pandas时间序列核心工具

在金融时间序列清洗中,时间对象不是简单的字符串,而是承载频率、时区、交易日历与对齐规则的“结构化坐标”。Pandas 提供了五个核心时间工具:Timestamp(单个时间点)、DatetimeIndex(时间点索引)、Period(周期区间)、Timedelta(时间差)、DateOffset(日历偏移)。理解它们的定位差异,是后续重采样、对齐与缺失值处理的基础。

一、核心原理:五个工具的分工

可以把它们理解为“点、轴、段、量、规则”五个层次。Timestamp 是标量时间点,类似 Python 的 datetime,但支持纳秒精度和丰富属性;DatetimeIndex 是 Timestamp 的集合,构成 Series/DataFrame 的时间轴;Period 表示一个固定频率的区间(如“2024-03”整月),适合月度、季度财报数据;Timedelta 是精确的物理时长(如 3 天 5 小时),用于加减运算;DateOffset 是“日历规则”偏移,如“下一个月末”“下一个工作日”,会考虑月份长度、节假日等业务语义。

关键区别:Timedelta 是“绝对时长”,DateOffset 是“日历规则”。例如 1 月 31 日加 1 个月,Timedelta 无法表达,而 DateOffset(months=1) 会得到 2 月 29 日(闰年)或 2 月 28 日。
Pandas 时间工具的五层定位 Timestamp 单个时间点 DatetimeIndex 时间点索引轴 Period 固定频率区间 Timedelta 绝对物理时长 DateOffset 日历规则 点 → 轴 → 段 → 量 → 规则:从标量到索引,从区间到运算,从物理时长到业务日历 金融场景:行情时间戳、交易日索引、月度财报、持仓久期、月末调仓 对齐核心:DatetimeIndex 提供坐标,Timedelta 做精确位移,DateOffset 做日历位移,Period 做频率转换 五者协同,才能完成金融时间序列的清洗、对齐与重采样

二、方法流程:创建与常用操作

下面按“创建 → 属性 → 运算 → 转换”四步走,覆盖五个工具的高频用法。

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月)
此案例体现了 Period → Timestamp → DatetimeIndex 的转换链,以及 DateOffset 在“月末对齐”中的业务价值。若直接用 Timedelta(30) 平移,会因月份长度不同产生错位。

四、误区与复盘

误区表现正确做法
用 Timedelta 代替 DateOffset1月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 标准化
复盘要点:金融时间序列的“时间”往往带有业务日历属性。清洗前先问三个问题——这是时间点还是区间?是自然日还是交易日?是绝对时长还是日历规则?答案决定你选 Timestamp、Period、Timedelta 还是 DateOffset。

掌握这五个工具后,后续的重采样、滚动窗口、缺失值填充与多表对齐都将有稳固的坐标基础。建议在真实行情与财报数据上反复练习创建、转换与运算,形成对时间语义的直觉。