股价、订单、传感器、日志——真实数据大多带着时间戳。pandas 对时间序列的支持深到什么程度?用时间当索引,切片比数组还顺手。这一章是做金融、运营、IoT 分析同学的必修课。
🕐 三种时间概念
from datetime import datetime
now = datetime.now() # 时刻:2026-09-20 14:00:00
now.year, now.month, now.day # 各字段随意访问
now.strftime("%Y-%m-%d") # 格式化输出
datetime.strptime("2026-09-20", "%Y-%m-%d") # 字符串解析(较慢)
pandas 用 Timestamp(时刻)和 Period(时期,如「2026 年 9 月」这个整月)扩展了 datetime,而 to_datetime 是万能入口:
dates = pd.to_datetime(["2026-09-01", "2026-09-02"])
ts = pd.Series(np.arange(2), index=dates)
🔍 时间索引:切片爽到飞起
ts = pd.Series(rng.standard_normal(1000),
index=pd.date_range("2024-01-01", periods=1000))
ts["2024-05"] # 直接取一整月!
ts["2024"] # 取一整年
ts["2024-05-01":"2024-06-15"] # 切片(含尾)
ts.truncate(after="2024-05-30") # 截断
重复时间戳用 ts.index.is_unique 检查、ts.groupby(level=0).mean() 聚合去重。
📅 date_range 与频率偏移
pd.date_range("2026-04-01", "2026-06-01") # 默认按天
pd.date_range("2026-04-01", periods=20, freq="W-MON") # 每周一
pd.date_range(start="2026-01-01", periods=10, normalize=True) # 归零到午夜
频率代码速查:D 天、B 工作日、H 小时、M(月末)、Q(季度末)、A(年末)、W-MON 每周一、MS 月初——还可以加倍数 4H 每 4 小时。
⏪ shift:对比的魔法
时间序列分析里「和上一期比」无处不在,shift 就是那个「上一期」:
ts.shift(1) # 整体后移一位
df["pct_change"] = ts / ts.shift(1) - 1 # 环比涨跌幅!
ts.shift(2, freq="M") # 移动的是时间戳不是数据(重对齐用)
🌍 时区:不是玄学,是 tz 参数
ts_utc = ts.tz_localize("UTC") # 给「naive」时间贴上时区
ts_utc.tz_convert("Asia/Shanghai") # 转换到另一时区
# 两个不同时区的对象做运算,自动统一到 UTC
⚠️ 经验:内部存储一律 UTC,展示时再转本地时区,能避开夏令时的绝大多数坑。
📆 Period:把「一段时期」当元素
p = pd.Period("2026-09", freq="M") # 「2026年9月」这个月
p + 5 # 2027年2月,直接做时期运算
# Timestamp ↔ Period 互转
ts.to_period("M") # 时间戳序列 → 月时期序列
季度数据处理(财年 Q-DEC 等)在会计/财报场景是刚需,书里有完整示例。
⚖️ resample:重采样是时间序列的心脏
把高频数据折叠成低频(降采样)或反向插值(升采样):
ts.resample("M").mean() # 按月取均值
ts.resample("M", kind="period").sum()
# 降采样的开闭区间语义:closed="left", label="left" 控制边界归哪组
ohlc = ts.resample("5min").ohlc() # 金融五分钟 K 线:open/high/low/close
upsampled = ts.resample("D").asfreq() # 升采样只取频点
upsampled = ts.resample("D").ffill() # 或前向填充
📈 rolling:移动窗口与平滑
ts.rolling(30).mean() # 30 日均线——消除噪声看趋势
ts.rolling(30, min_periods=20).std() # 窗口内至少 20 个有效值才算
ts.ewm(span=30).mean() # 指数加权:近期数据权重更大
ts.rolling(60).corr(other) # 滚动相关系数:相关性随时间变化
ts.expanding().mean() # 扩展窗口:从起点到当前的累计均值
移动窗口是技术分析(均线、布林带)、运营监控(7 日均值告警)的基础。rolling("30D") 还能按时间长度而非条数开窗——不规则采样的救星。
📌 本章小结:时间当索引,
ts["2024-05"]直取整月;date_range(freq="W-MON")生成规则序列;ts/ts.shift(1)-1就是环比;时区先tz_localize再tz_convert;resample 折叠时间、rolling 平滑噪声,这俩组合是时间序列分析的主武器。