Python案例如何用Pandas做数据分组重采频率

wen python案例 2

Python案例详解如何用Pandas做数据分组重采样(附实战代码)

目录导读

  1. 什么是数据分组重采样?为什么它如此重要?
  2. Pandas重采样基础:resample() 与 groupby() 的区别
  3. 高频实战案例:股票交易数据按周重采样
  4. 按类别分组后重采样:零售销售数据月汇总
  5. 时间序列 + 多列聚合:同时计算均值、总和与最大值
  6. 常见错误与调优技巧
  7. 问答环节:你可能会遇到的5个关键问题

什么是数据分组重采样?为什么它如此重要?

在数据分析中,原始数据往往以“秒级”或“日级”频率记录,但业务决策通常需要“周级”或“月级”的汇总视图。数据分组重采样,即先按某个分类字段(如城市、产品ID)分组,再对每个组内的时间序列数据进行频率转换(如从每日转为每周)。

Python案例如何用Pandas做数据分组重采频率

为什么重要?

  • 减少数据量,提升后续模型训练速度
  • 匹配业务汇报周期(如周报、月报)
  • 消除高频噪声,暴露长期趋势

案例场景:某电商平台需要按“商品类别”统计“每周平均销量”,原始数据是每分钟的订单记录,直接按周平均会掩盖类别差异,必须先分组后重采样。


Pandas重采样基础:resample() 与 groupby() 的区别

核心API对比

操作 适用场景 关键参数
df.resample('W').mean() 单时间序列 频率字符串('W','M','Q')
df.groupby('category').resample('W').mean() 多分类+时间序列 先分组,再重采样

实现逻辑模型

原始数据 → 按category分组 → 每组形成一个子DataFrame → 每组调用resample() → 合并结果

代码示例(模拟数据)

import pandas as pd
import numpy as np
# 生成模拟数据:2种商品,2023年每日数据
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
df = pd.DataFrame({
    'date': np.tile(dates, 2),
    'product': ['A']*len(dates) + ['B']*len(dates),
    'sales': np.random.randint(100, 500, len(dates)*2)
})
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace=True)
# 关键操作:分组 + 重采样
grouped_resampled = df.groupby('product').resample('W').sum()
print(grouped_resampled.head())

输出解释:每一行代表某商品在某周的总销售额,索引为 (product, date) 多级索引。


高频实战案例:股票交易数据按周重采样

业务需求

给定股票代码、日期、收盘价、交易量,要求计算每只股票 每周最高价、最低价、平均价和总交易量

完整代码

import yfinance as yf  # 真实数据源,若无法联网可用本地csv替代
# 下载股票数据(示例:AAPL与GOOG)
tickers = ['AAPL', 'GOOG']
data = yf.download(tickers, start='2023-01-01', end='2023-12-31', group_by='ticker')
# 准备多级索引
df_list = []
for ticker in tickers:
    temp = data[ticker].copy()
    temp['ticker'] = ticker
    df_list.append(temp)
df = pd.concat(df_list)
df.reset_index(inplace=True)
df.set_index(['ticker', 'Date'], inplace=True)
# 分组重采样(关键步骤)
weekly = df.groupby(level='ticker').resample('W').agg({
    'Close': ['max', 'min', 'mean'],
    'Volume': 'sum'
})
print(weekly.head(10))

输出结果样式

                         Close                  Volume
                           max    min      mean      sum
ticker Date                                           
AAPL   2023-01-08  133.34  126.36  129.85  62050000
       2023-01-15  135.45  131.26  133.12  58420000
GOOG   2023-01-08   89.12   85.30   87.45  43010000

关键点groupby(level='ticker') 用于处理多级索引的第一层分组。


按类别分组后重采样:零售销售数据月汇总

数据特点

每行包含:store_id, date, department, sales_amount

优化写法(避免多级索引混乱)

# 读取零售数据(假设已导入)
df = pd.read_csv('retail_sales.csv', parse_dates=['date'])
# 方法1:先set_index再groupby
df.set_index('date', inplace=True)
monthly = df.groupby('department').resample('M')['sales_amount'].sum().reset_index()
print(monthly.head())
# 方法2:使用groupby + apply(适合更复杂逻辑)
def monthly_sum(group):
    return group.resample('M')['sales_amount'].sum()
result = df.groupby('department').apply(monthly_sum)

注意事项

  • 如果数据量大,reset_index() 可以避免多级索引的调用代价
  • 对于缺失月份,可使用 .asfreq() 补全为空值

时间序列 + 多列聚合:同时计算均值、总和与最大值

高级聚合技巧

# 假设有4列:temperature, humidity, wind_speed, pressure
df = pd.read_csv('weather_daily.csv', parse_dates=['date'])
df.set_index('date', inplace=True)
# 按城市分组,按月重采样,并指定每列的聚合方式
monthly_weather = df.groupby('city').resample('M').agg({
    'temperature': 'mean',
    'humidity': 'mean',
    'wind_speed': 'max',
    'pressure': ['min', 'max']
})
print(monthly_weather.head())

输出截图说明

  • 列名变为多级:temperature 列变 ('temperature', 'mean')
  • 可通过 monthly_weather.columns = ['_'.join(col).strip() for col in monthly_weather.columns] 简化

常见错误与调优技巧

错误1:忘记将时间列设为索引

  • 后果resample() 报错 AttributeError: 'Index' object has no attribute 'freq'
  • 解决df.set_index('date', inplace=True)

错误2:分组后索引层级混乱

  • 现象groupby('A').resample('M') 返回三层索引
  • 解决:清预期层级,使用 .reset_index(level=1, drop=True) 或直接 reset_index()

调优技巧

  1. 使用 sort=False:若原始数据已排序,可提速
  2. 使用 apply 替代循环:永远不要写 for group in df.groupby('A')
  3. 数据量超1亿行:考虑 Daskmodin 扩展库

问答环节:你可能会遇到的5个关键问题

Q1:重采样后数据变少了,是不是丢失了信息? A:不是丢失,而是聚合,每日数据 -> 每周平均”,压缩了粒度但保留了趋势,若需保留极端值,可用 max/min 聚合。

Q2:如何从周数据再重采样为月数据? A:直接 resample('M') 即可,Pandas会自动识别基于周索引的周期端点。

Q3:分组+重采样后如何还原为扁平DataFrame? A:使用 reset_index() 并重命名列,

monthly.reset_index(inplace=True)
monthly['date'] = monthly['date'].dt.to_period('M')

Q4:有些组在特定时间段没有数据,如何补全? A:使用 .asfreq('W', fill_value=0) 在重采样后填充缺失的时间点。

Q5:groupby().resample()resample().groupby() 有区别吗? A:前者是先分组再对每组分别重采样(常见需求),后者会先对整体时间序列重采样再分组,逻辑相反,通常不推荐。


Pandas的分组重采样功能是时间序列分析的“杀手锏”,通过本文的案例,你已掌握以下核心技能:

  • 区分 resample()groupby().resample()
  • 处理多级索引带来的复杂性
  • 针对不同业务场景选择合适的聚合函数

你可以打开你的数据集,尝试按“地区-产品-月份”做一次重采样分析,你会发现隐藏在高频数据下的业务规律。

抱歉,评论功能暂时关闭!