时间序列 #
时间序列概述 #
Pandas 提供了强大的时间序列处理功能,是金融、气象、物联网等领域的核心工具。
text
┌─────────────────────────────────────────────────────────────┐
│ 时间序列功能 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 时间创建 │
│ ├── pd.Timestamp 时间戳 │
│ ├── pd.DatetimeIndex 时间索引 │
│ ├── pd.date_range 日期范围 │
│ └── pd.to_datetime 转换为时间 │
│ │
│ 时间操作 │
│ ├── dt 访问器 时间属性 │
│ ├── resample 重采样 │
│ ├── rolling 滚动窗口 │
│ └── shift 时间偏移 │
│ │
│ 时间计算 │
│ ├── pd.Timedelta 时间差 │
│ ├── pd.DateOffset 日期偏移 │
│ └── 时区处理 │
│ │
└─────────────────────────────────────────────────────────────┘
时间创建 #
Timestamp #
python
import pandas as pd
import numpy as np
# 创建时间戳
ts = pd.Timestamp('2024-01-01')
print(ts) # 2024-01-01 00:00:00
# 指定时间
ts = pd.Timestamp('2024-01-01 10:30:00')
ts = pd.Timestamp(year=2024, month=1, day=1, hour=10, minute=30)
# 从 Unix 时间戳
ts = pd.Timestamp(1704067200, unit='s')
# 当前时间
ts = pd.Timestamp.now()
DatetimeIndex #
python
# 创建时间索引
idx = pd.DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03'])
print(idx)
# 使用 date_range
idx = pd.date_range('2024-01-01', periods=5)
print(idx)
# DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05'], dtype='datetime64[ns]', freq='D')
# 指定频率
idx = pd.date_range('2024-01-01', periods=5, freq='H') # 小时
idx = pd.date_range('2024-01-01', periods=5, freq='M') # 月末
idx = pd.date_range('2024-01-01', periods=5, freq='MS') # 月初
idx = pd.date_range('2024-01-01', periods=5, freq='W') # 周
idx = pd.date_range('2024-01-01', periods=5, freq='Q') # 季末
idx = pd.date_range('2024-01-01', periods=5, freq='Y') # 年末
# 指定起止日期
idx = pd.date_range('2024-01-01', '2024-12-31', freq='M')
# 工作日
idx = pd.bdate_range('2024-01-01', periods=5) # 只包含工作日
to_datetime #
python
# 字符串转换
dates = ['2024-01-01', '2024-01-02', '2024-01-03']
dt = pd.to_datetime(dates)
print(dt)
# 指定格式
dates = ['01-01-2024', '01-02-2024']
dt = pd.to_datetime(dates, format='%m-%d-%Y')
# 处理错误
dates = ['2024-01-01', 'invalid', '2024-01-03']
dt = pd.to_datetime(dates, errors='coerce') # 无效值变为 NaT
dt = pd.to_datetime(dates, errors='ignore') # 保持原样
# 解析多列
df = pd.DataFrame({
'year': [2024, 2024],
'month': [1, 2],
'day': [1, 1]
})
dt = pd.to_datetime(df[['year', 'month', 'day']])
时间属性(dt 访问器) #
python
# 创建时间序列
df = pd.DataFrame({
'date': pd.date_range('2024-01-01 10:30:00', periods=5, freq='D')
})
# 提取时间属性
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
df['hour'] = df['date'].dt.hour
df['minute'] = df['date'].dt.minute
df['second'] = df['date'].dt.second
# 星期
df['dayofweek'] = df['date'].dt.dayofweek # 0=Monday
df['day_name'] = df['date'].dt.day_name()
df['weekday'] = df['date'].dt.weekday
# 年中位置
df['dayofyear'] = df['date'].dt.dayofyear
df['weekofyear'] = df['date'].dt.isocalendar().week
df['quarter'] = df['date'].dt.quarter
# 判断
df['is_month_start'] = df['date'].dt.is_month_start
df['is_month_end'] = df['date'].dt.is_month_end
df['is_leap_year'] = df['date'].dt.is_leap_year
print(df)
时间差(Timedelta) #
python
# 创建时间差
td = pd.Timedelta(days=1)
td = pd.Timedelta(weeks=1, days=2, hours=3)
# 字符串
td = pd.to_timedelta('1 day')
td = pd.to_timedelta('1 day 2 hours')
td = pd.to_timedelta(['1 day', '2 days', '3 days'])
# 时间运算
ts = pd.Timestamp('2024-01-01')
print(ts + pd.Timedelta(days=7)) # 2024-01-08
# 时间差运算
df = pd.DataFrame({
'start': pd.date_range('2024-01-01', periods=5),
'end': pd.date_range('2024-01-10', periods=5)
})
df['duration'] = df['end'] - df['start']
df['days'] = df['duration'].dt.days
print(df)
重采样(resample) #
重采样是时间序列分析的核心操作,用于改变时间频率。
python
# 创建时间序列
dates = pd.date_range('2024-01-01', periods=100, freq='D')
df = pd.DataFrame({
'date': dates,
'value': np.random.randn(100).cumsum()
})
df.set_index('date', inplace=True)
# 降采样(高频 → 低频)
# 月度均值
monthly = df.resample('M').mean()
print(monthly)
# 周度求和
weekly = df.resample('W').sum()
# 季度统计
quarterly = df.resample('Q').agg({
'value': ['mean', 'std', 'count']
})
# 升采样(低频 → 高频)
# 日度数据 → 小时数据
hourly = df.resample('H').asfreq() # 产生缺失值
hourly = df.resample('H').ffill() # 前向填充
hourly = df.resample('H').bfill() # 后向填充
hourly = df.resample('H').interpolate() # 插值
# 自定义聚合
result = df.resample('W').agg({
'value': ['mean', 'std', 'min', 'max']
})
# OHLC(开高低收)
ohlc = df.resample('W').ohlc()
print(ohlc)
重采样频率 #
text
┌─────────────────────────────────────────────────────────────┐
│ 重采样频率代码 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 代码 说明 别名 │
│ ────── ──────────────── ──────────────────────────── │
│ S 秒 │
│ T/min 分钟 │
│ H 小时 │
│ D 天 │
│ W 周 │
│ M 月末 month │
│ MS 月初 │
│ Q 季末 quarter │
│ QS 季初 │
│ Y/year 年末 │
│ YS/year 年初 │
│ B 工作日 │
│ BH 工作小时 │
│ │
└─────────────────────────────────────────────────────────────┘
滚动窗口(rolling) #
python
# 创建时间序列
dates = pd.date_range('2024-01-01', periods=100, freq='D')
df = pd.DataFrame({
'date': dates,
'value': np.random.randn(100).cumsum()
})
df.set_index('date', inplace=True)
# 滚动均值(移动平均)
df['rolling_mean'] = df['value'].rolling(window=7).mean()
# 滚动标准差
df['rolling_std'] = df['value'].rolling(window=7).std()
# 滚动最大/最小
df['rolling_max'] = df['value'].rolling(window=7).max()
df['rolling_min'] = df['value'].rolling(window=7).min()
# 滚动求和
df['rolling_sum'] = df['value'].rolling(window=7).sum()
# 自定义函数
df['rolling_median'] = df['value'].rolling(window=7).median()
# 最小观测数
df['rolling_mean'] = df['value'].rolling(window=7, min_periods=1).mean()
# 居中窗口
df['centered'] = df['value'].rolling(window=7, center=True).mean()
print(df.head(10))
滚动窗口方法 #
python
# 常用方法
df['value'].rolling(7).mean() # 均值
df['value'].rolling(7).std() # 标准差
df['value'].rolling(7).var() # 方差
df['value'].rolling(7).sum() # 求和
df['value'].rolling(7).min() # 最小值
df['value'].rolling(7).max() # 最大值
df['value'].rolling(7).median() # 中位数
df['value'].rolling(7).quantile(0.5) # 分位数
df['value'].rolling(7).corr() # 相关系数
df['value'].rolling(7).cov() # 协方差
df['value'].rolling(7).skew() # 偏度
df['value'].rolling(7).kurt() # 峰度
# 应用自定义函数
df['value'].rolling(7).apply(lambda x: x.max() - x.min())
扩展窗口(expanding) #
python
# 扩展窗口(从开始到当前位置)
df['expanding_mean'] = df['value'].expanding().mean()
df['expanding_sum'] = df['value'].expanding().sum()
df['expanding_max'] = df['value'].expanding().max()
# 指定最小观测数
df['expanding_mean'] = df['value'].expanding(min_periods=1).mean()
指数加权移动平均(ewm) #
python
# 指数加权移动平均
df['ewm_mean'] = df['value'].ewm(span=7).mean()
df['ewm_std'] = df['value'].ewm(span=7).std()
# 指定衰减因子
df['ewm_mean'] = df['value'].ewm(alpha=0.3).mean()
df['ewm_mean'] = df['value'].ewm(halflife=3).mean()
时间偏移(shift) #
python
# 向后移动
df['shifted'] = df['value'].shift(1) # 下移一行
df['shifted'] = df['value'].shift(7) # 下移 7 行
# 向前移动
df['shifted'] = df['value'].shift(-1) # 上移一行
# 计算变化
df['diff'] = df['value'].diff() # 与前一行的差
df['diff_7'] = df['value'].diff(7) # 与前 7 行的差
# 百分比变化
df['pct_change'] = df['value'].pct_change()
时区处理 #
python
# 创建时区无关时间
ts = pd.Timestamp('2024-01-01 10:00:00')
# 添加时区
ts_utc = ts.tz_localize('UTC')
print(ts_utc) # 2024-01-01 10:00:00+00:00
# 转换时区
ts_ny = ts_utc.tz_convert('America/New_York')
ts_shanghai = ts_utc.tz_convert('Asia/Shanghai')
print(ts_shanghai) # 2024-01-01 18:00:00+08:00
# 创建带时区的时间序列
idx = pd.date_range('2024-01-01', periods=5, tz='Asia/Shanghai')
print(idx)
# 时区列表
from pytz import all_timezones
print(all_timezones[:10])
时间序列实战案例 #
python
# 股票数据分析
dates = pd.date_range('2023-01-01', '2023-12-31', freq='B') # 工作日
prices = pd.DataFrame({
'open': 100 + np.random.randn(len(dates)).cumsum(),
'high': 101 + np.random.randn(len(dates)).cumsum(),
'low': 99 + np.random.randn(len(dates)).cumsum(),
'close': 100 + np.random.randn(len(dates)).cumsum(),
'volume': np.random.randint(1000000, 10000000, len(dates))
}, index=dates)
# 计算技术指标
prices['ma_5'] = prices['close'].rolling(5).mean()
prices['ma_20'] = prices['close'].rolling(20).mean()
prices['daily_return'] = prices['close'].pct_change()
prices['volatility'] = prices['daily_return'].rolling(20).std()
# 月度统计
monthly_stats = prices.resample('M').agg({
'open': 'first',
'high': 'max',
'low': 'min',
'close': 'last',
'volume': 'sum'
})
print(monthly_stats)
下一步 #
掌握了时间序列后,接下来学习 数据可视化,了解如何使用 Pandas 进行数据可视化!
最后更新:2026-04-04