如何基于Pandas GroupBy双分组变量计算相对频率并可视化?
问题描述
给定如下数据:
import datetime import pandas as pd df = pd.DataFrame({'datetime': [datetime.datetime(2024, 11, 27, 0), datetime.datetime(2024, 11, 27, 1), datetime.datetime(2024, 11, 28, 0), datetime.datetime(2024, 11, 28, 1), datetime.datetime(2024, 11, 28, 2)], 'product': ['Apple', 'Banana', 'Banana', 'Apple', 'Banana']})
数据预览:
| datetime | product | |
|---|---|---|
| 0 | 2024-11-27 00:00:00 | Apple |
| 1 | 2024-11-27 01:00:00 | Banana |
| 2 | 2024-11-28 00:00:00 | Banana |
| 3 | 2024-11-28 01:00:00 | Apple |
| 4 | 2024-11-28 02:00:00 | Banana |
需求是绘制每日各产品销量的相对频率:比如2024-11-27日苹果和香蕉各占50%;2024-11-28日苹果占1/3,香蕉占2/3。
现有实现代码:
absolute_frequencies = df.groupby([pd.Grouper(key='datetime', freq='D'), 'product']).size().reset_index(name='count') total_counts = absolute_frequencies.groupby('datetime')['count'].transform('sum') absolute_frequencies['relative_frequency'] = absolute_frequencies['count'] / total_counts absolute_frequencies.pivot(index='datetime', columns='product', values='relative_frequency').plot()
你认为可以更简洁,因为计算绝对频率时仅需一行代码:
df.groupby([pd.Grouper(key='datetime', freq='D'), 'product']).size().unstack('product').plot(kind='line')
简洁实现方案
这里提供两种更紧凑的写法,无需创建中间变量,直接实现相对频率计算与绘图:
方法一:基于分组除法
(df.groupby([pd.Grouper(key='datetime', freq='D'), 'product']) .size() .unstack('product') .div(df.groupby(pd.Grouper(key='datetime', freq='D')).size(), axis=0) .plot())
方法二:使用value_counts(normalize=True)
(df.assign(date=df['datetime'].dt.date) .groupby('date')['product'] .value_counts(normalize=True) .unstack('product') .plot())
方案说明
方法一:
- 先按日期+产品分组得到绝对频率,
unstack将产品转为列格式 - 调用
div方法,按行(axis=0)除以每日总销量(单独按日期分组计算size) - 直接链式调用
plot生成图表
- 先按日期+产品分组得到绝对频率,
方法二:
- 先提取日期列(
dt.date)简化分组维度 - 按日期分组后,用
value_counts(normalize=True)直接得到组内相对频率 unstack转换格式后绘图,逻辑更直观
- 先提取日期列(
两种写法都实现了和你现有代码完全一致的效果,且更贴近绝对频率的简洁风格。
内容的提问来源于stack exchange,提问作者Qaswed
相关产品推荐
相关产品推荐

