如何为Pandas DataFrame各列自定义GroupBy函数?如何捕捉跨季节值变化?
搞定Pandas Groupby自定义函数+季节间数值变化的方案
咱先从你问的第一个问题说起:怎么用groupby给每列应用自定义函数,得到想要的结果。我给你分两种常见场景,配示例代码,一看就懂。
一、Groupby后为每列应用自定义函数
首先咱先造个贴近业务的示例数据:
import pandas as pd import numpy as np # 构造包含ID、年份、季节、销量、利润的示例DataFrame data = { 'ID': ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'C'], 'Year': [2021, 2021, 2022, 2021, 2022, 2021, 2022, 2022], 'Season': ['春', '秋', '春', '夏', '夏', '春', '秋', '冬'], 'Sales': [100, 150, 120, 80, 90, 200, 220, 180], 'Profit': [20, 30, 25, 15, 18, 40, 45, 35] } df = pd.DataFrame(data)
1. 所有数值列共用同一个自定义函数
比如你想给每个ID的销量、利润都计算均值、最大值,还有自定义的「峰值与均值的差值」,可以这么写:
# 定义自定义统计函数,返回Series格式方便后续展开 def custom_stats(x): return pd.Series({ 'mean': x.mean(), 'max': x.max(), 'peak_diff': x.max() - x.mean() }) # 按ID分组,对Sales和Profit列应用自定义函数 result = df.groupby('ID')[['Sales', 'Profit']].apply(custom_stats) # 把多层索引展开,让结果更直观 result = result.unstack(level=1)
执行后你会得到一个清晰的结果表,每个ID对应每列的三个统计值。
2. 不同列用不同的自定义函数
如果想给销量算总和和变异系数,给利润算中位数和调整后的最小值,用agg方法的字典传参就很灵活:
# 定义两个自定义函数 def coefficient_of_variation(x): # 变异系数:标准差/均值*100,反映数据离散程度 return x.std() / x.mean() * 100 def adjusted_min_profit(x): # 自定义利润最小值:实际最小值减5 return x.min() - 5 # 按ID分组,指定每列对应的函数,还能自定义结果列名 result_custom = df.groupby('ID').agg( 销量总和=('Sales', 'sum'), 销量变异系数=('Sales', coefficient_of_variation), 利润中位数=('Profit', 'median'), 调整后利润最小值=('Profit', adjusted_min_profit) )
这种方式可以精准控制每列的计算逻辑,还能直接给结果列起业务化名称,非常实用。
二、捕捉同一ID在多年多季节的数值变化
针对部分ID有多年多季节数据的情况,分两种常见场景处理:
1. 同一年份内不同季节的变化(环比)
先给季节排序(避免乱序导致计算错误),然后按ID+年份分组,用diff()或pct_change()计算变化:
# 给季节指定顺序,方便排序 season_rank = {'春':1, '夏':2, '秋':3, '冬':4} df['Season_rank'] = df['Season'].map(season_rank) # 按ID、年份、季节排序 df_sorted = df.sort_values(['ID', 'Year', 'Season_rank']) # 计算同一年内,当前季节与上一季节的销量差值和变化率 df_sorted['销量季节差值'] = df_sorted.groupby(['ID', 'Year'])['Sales'].diff() df_sorted['销量季节变化率(%)'] = df_sorted.groupby(['ID', 'Year'])['Sales'].pct_change() * 100
这样你就能看到每个ID每年里,春到秋、秋到冬这类季节间的销量波动。
2. 同一季节不同年份的变化(同比)
按ID+季节分组,计算跨年度的变化:
# 按ID、季节、年份排序 df_yoy_sorted = df.sort_values(['ID', 'Season', 'Year']) # 计算同一季节,今年与去年的销量差值和同比变化率 df_yoy_sorted['销量同比差值'] = df_yoy_sorted.groupby(['ID', 'Season'])['Sales'].diff() df_yoy_sorted['销量同比变化率(%)'] = df_yoy_sorted.groupby(['ID', 'Season'])['Sales'].pct_change() * 100
比如ID A的2022年春 vs 2021年春的销量变化,就能直接看到。
3. 用透视表直观对比所有季节数据
如果想一次性查看所有年份-季节的数值对比,用pivot_table转成宽表更清晰:
# 生成透视表:行是ID,列是年份-季节,值是销量 pivot_df = df.pivot_table(index='ID', columns=['Year', 'Season'], values='Sales', aggfunc='first') # 直接计算指定季节的跨年度差值,比如2022春 vs 2021春 pivot_df['2022春_vs_2021春'] = pivot_df[(2022, '春')] - pivot_df[(2021, '春')]
这种方式适合做全局对比,一眼就能看到每个ID的季节数据变化趋势。
内容的提问来源于stack exchange,提问作者wolverinejohn
相关产品推荐
相关产品推荐

