0Pricing
Pandas & NumPy Academy · 课时

重采样时间序列

使用 resample('ME').sum() 将每日数据降采样为每月数据,并通过向前填充补齐缺失的时间间隔。

重采样时间序列 是 CoddyKit 上的免费 Pandas & NumPy Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Pandas & NumPy Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Pandas & NumPy Academy 课程共包含 4 节课。

什么是重采样

重采样会改变时间序列的频率。降采样会降低频率,例如将每日数据转换为月度总计。升采样会提高频率,例如将月度数据转换为每日数据,并使用插值填补间隔。两种操作都要求使用 DatetimeIndex,并通过 resample() 方法执行;该方法是 Pandas 面向时间的 groupby() 版本。

resample() 方法

df.resample(rule) 会创建一个 DatetimeIndexResampler 对象,其中 rule 是频率偏移别名。与 groupby() 类似,在链式调用聚合方法之前不会进行任何计算。常见规则包括:'D'(天)、'W'(周)、'ME'(月末)、'QE'(季度末)和 'YE'(年末)。DataFrame 必须具有 DatetimeIndex。

import pandas as pd
import numpy as np

np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=90, freq='D')
df = pd.DataFrame({'sales': np.random.randint(100, 500, 90)}, index=dates)

print(df.head())
print('Shape:', df.shape)  # (90, 1) -- 90 daily rows

降采样:从每日到每月

要将每日数据降采样为月度数据,请调用 resample('ME') 并链接一个聚合函数。sum() 会得到月度总计;mean() 会得到月度平均值;last() 会得到每个周期的最后一个值。结果中每个周期对应一行,并以周期结束日期作为索引标签。

# Monthly totals
monthly_sum = df.resample('ME').sum()
print(monthly_sum)
# sales
# 2024-01-31    9876
# 2024-02-29    8765
# 2024-03-31    9234

# Monthly averages
monthly_mean = df.resample('ME').mean().round(1)
print(monthly_mean)

降采样为每周数据

使用 'W' 重采样可以按以星期日结束的日历周进行聚合。如果希望以星期一为周末,请使用 'W-MON'。Pandas 会将每周内的所有日期分到一起,然后执行聚合。这对于每周生成一行汇总数据的周报非常有用。

# Weekly sum
weekly = df.resample('W').sum()
print(weekly.head())
# sales
# 2024-01-07    2010  <- Jan 1-7
# 2024-01-14    2340  <- Jan 8-14
# ...

# Weekly max and count using agg()
weekly_stats = df.resample('W').agg(['sum', 'mean', 'max'])
print(weekly_stats.head())

应用多个聚合函数

与 groupby() 一样,您可以在重采样器上链接 .agg(),一次计算多个统计量。您可以传入函数名称列表,或传入字典来执行命名聚合。这是构建全面时间序列汇总表最高效的方法。

monthly_stats = df.resample('ME').agg(
    total_sales=('sales', 'sum'),
    avg_sales=('sales', 'mean'),
    peak_sales=('sales', 'max'),
    days_counted=('sales', 'count')
)
print(monthly_stats.round(1))
#             total_sales  avg_sales  peak_sales  days_counted
# 2024-01-31         9876      318.6         499            31

用于金融数据的 OHLC 重采样

对于金融时间序列,.ohlc() 方法会对每个周期进行重采样,得到开盘价、最高价、最低价和收盘价(OHLC)——这是标准的蜡烛图表示方式。此方法仅适用于表示价格或水平值的数值数据。输入中的每一列都会在输出中对应四个 OHLC 列。

# OHLC monthly resampling
ohlc = df['sales'].resample('ME').ohlc()
print(ohlc)
#             open  high   low  close
# 2024-01-31   365   499   101    243
# 2024-02-29   ...

升采样:从每月到每日

升采样会提高频率,从而为原始数据中不存在的时间戳创建行。这些新行最初包含 NaN。随后,您需要根据数据特点选择合适的方法填充它们:ffill()(向前填充——延续最后一个已知值)或 bfill()(向后填充——使用下一个已知值),也可以使用 interpolate() 进行平滑插值。

# Monthly data
monthly = pd.Series(
    [100, 120, 115],
    index=pd.date_range('2024-01-31', periods=3, freq='ME')
)
print(monthly)

# Upsample to daily (creates NaN rows)
daily = monthly.resample('D').asfreq()
print(daily.head(10))
# 2024-01-31    100.0
# 2024-02-01      NaN  <- new row
# ...

填充升采样产生的间隔

升采样后,请填充为新时间戳创建的 NaN 间隔。ffill() 会将最后一个已知值向前传播,直到下一个实际观测值;当最后成交价仍然有效时,这种方法适用于价格数据。interpolate(method='linear') 会在观测值之间填入线性间隔的数值;这种方法适用于平滑的连续变量。

# Forward fill: carry monthly value forward to every day
daily_ffill = monthly.resample('D').ffill()
print(daily_ffill.head(35))
# 2024-01-31    100
# 2024-02-01    100  <- forward filled
# ...
# 2024-02-29    120  <- new month value

# Linear interpolation
daily_interp = monthly.resample('D').interpolate(method='linear')
print(daily_interp.head(10))

在分组内重采样

您可以结合使用 groupby() 和 resample(),分别在每个分组内进行重采样。对于具有 DatetimeIndex 的 DataFrame,调用 groupby(column).resample(rule)。这样会生成一个带有 MultiIndex 的结果:外层级别是分组键,内层级别是重采样后的时间周期。这对于按产品或地区进行时间序列分析非常有用。

df2 = pd.DataFrame({
    'product': ['A', 'B', 'A', 'B', 'A', 'B'],
    'sales': [100, 150, 120, 130, 110, 160]
}, index=pd.date_range('2024-01-01', periods=6, freq='ME'))

# Monthly sum per product
result = df2.groupby('product').resample('QE').sum()
print(result)

自定义偏移锚点

默认情况下,'ME' 以日历月末日期为锚点。对于非标准财务周期,请使用 'QS-APR'(从四月开始的季度)或 'YS-OCT'(从十月开始的年度)等偏移。Pandas 支持许多带锚点的偏移别名。处理非日历财务周期时,请查阅 Pandas 文档获取完整列表。

# Fiscal year starting in April
fiscal_annual = df.resample('YE-MAR').sum()
print(fiscal_annual)
# sales
# 2024-03-31    XXXX  <- April 2023 to March 2024

# Quarter starting in April
fiscal_q = df.resample('QE-MAR').mean().round(0)
print(fiscal_q)

检查重采样结果的完整性

重采样后,请始终验证结果是否合理。检查输出周期数量是否符合预期,是否存在缺失周期(查看输出中是否有 NaN),并且在使用 sum() 进行降采样时,月度总计之和是否等于原始每日数据之和。这些合理性检查可以发现频率字符串中的边界偏移错误以及缺失的日期范围。

monthly = df.resample('ME').sum()

# Verify: monthly totals should sum to daily total
assert monthly['sales'].sum() == df['sales'].sum(), 'Sum mismatch!'

# Verify: expected number of months
print('Months:', len(monthly))  # should be 3 for 90 days Jan-Mar

# Check for any NaN
print('NaN count:', monthly.isna().sum().sum())

快速检查

测试您对本课中时间序列重采样的理解。

课程回顾

在本课中,您学习了:resample() 是用于改变时间序列频率的面向时间的 groupby() 等效方法;降采样会聚合数据(从每日到每月,并使用 sum/mean);升采样会创建必须使用 ffill() 或 interpolate() 填充的新时间戳;此外,还可以结合 groupby() 和 resample() 执行分组级别的时间聚合。接下来,我们将探索移位和滞后特征。

常见问题解答

「重采样时间序列」课时是免费的吗?

是的 — 「重采样时间序列」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Pandas & NumPy Academy 课程的其余内容,请升级到 CoddyKit PRO。 Pandas & NumPy Academy 课程共包含 4 节课。

「重采样时间序列」这节课中我会学到什么?

使用 resample('ME').sum() 将每日数据降采样为每月数据,并通过向前填充补齐缺失的时间间隔。 你通过在浏览器中直接运行的动手代码来练习 Pandas & NumPy Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Pandas & NumPy Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Pandas & NumPy Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「重采样时间序列」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Pandas & NumPy Academy 课中编写并运行代码吗?

能。每节 Pandas & NumPy Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. DatetimeIndex 与周期范围
  2. 重采样时间序列
  3. 移动与滞后特征
  4. 提取时间特征
← 返回 Pandas & NumPy Academy