看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本例我们将进行分组计算,分组后得到一个堆叠数据,并对堆叠数据解除堆叠,最后再按要求格式化为百分数样式。此类操作会经常发生在业务数据透视场景下,一般都会有 Excel 来操作完成,今天我们使用 Python 的 pandas 的完成。
需求的源数据如下:
import pandas as pd
from io import StringIO
data = '''
CustomerID Category Repeat Date
1 A Y 2022-01-10
2 B N 2022-01-10
3 A N 2022-02-10
4 A N 2022-01-10
5 B Y 2022-01-10
6 B Y 2022-02-10
7 A Y 2022-01-10
8 B N 2022-02-10
9 A Y 2022-02-10
10 A N 2022-01-10
11 A Y 2022-02-10
12 B N 2022-01-10
13 A N 2022-01-10
14 A N 2022-02-10
15 B Y 2022-02-10
16 B Y 2022-01-10
17 A Y 2022-01-10
18 B N 2022-02-10
19 A Y 2022-02-10
20 A N 2022-01-10
'''
df = pd.read_csv(StringIO(data), sep=' ')
df
# ...
期望按 Category 分组,得到每日 Repeat 列 Y 值的占比,即 Y/(Y+N) 的百分比,结果如下:
'''
Date 2022-01-10 2022-02-10
Category
A 42.86% 60.00%
B 50.00% 50.00%
'''
接下来,我们分析下需求和方案。
根据需求要求,要按 ['Category', 'Date']
进行分组,分组后最关键的是计算 Y 值的占比,计算占比可以写一个函数,先计算 Y 的取值数据再除以当前组的总值数。
得到的分组数据是一个堆叠形式的数据,将其解除堆叠,第二层索引会出现在行索引上。
最后再利用 DataFrame 的 style 对象应用 format 方法进行百分数的格式化。
按照思路,先进行分组:
df.groupby(['Category', 'Date'])
# <pandas.core.groupby.generic.DataFrameGroupBy
# object at 0x7fa6e467edd0>
此时得到的是一个分组对象,每个分组包含各组的子 DataFrame。在计算时,只需要 Repeat 参与计算,因此我们可以取分组对象的 Repeat 的列,就得到了几个 Repeat 分组的子 Series。
df.groupby(['Category', 'Date']).Repeat
# <pandas.core.groupby.generic.SeriesGroupBy
# object at 0x7fa6e81cfeb0>
然后对这个分组对象应用函数:
(
df.groupby(['Category', 'Date'])
.Repeat
.apply(lambda x: (x=='Y').sum()/x.count())
)
'''
Category Date
A 2022-01-10 0.428571
2022-02-10 0.600000
B 2022-01-10 0.500000
2022-02-10 0.500000
Name: Repeat, dtype: float64
'''
定义的 lambda 函数中,(x=='Y')
得到一个布尔序列,代表子 Series 对应位置上的是否为 Y,由于 sum() 求值时, True 为 1,可以计算出有多少个 True,即得到有多少个值为 Y。分母上的 x.count()
表示子序列有多少个值。
上边代码得到的结果就是按 Category 分组下的每天 Y 值的占比。由于结果是一个堆叠形式,我们使用 unstack() 解除堆叠:
(
df.groupby(['Category', 'Date'])
.Repeat
.apply(lambda x: (x=='Y').sum()/x.count())
.unstack()
)
'''
Date 2022-01-10 2022-02-10
Category
A 0.428571 0.6
B 0.500000 0.5
'''
这样,Date 列就成为了列索引。
最后,使用 DataFrame 的 style 对象应用 format 方法进行百分数的格式化。
最终代码为:
(
df.groupby(['Category', 'Date'])
.Repeat
.apply(lambda x: (x=='Y').sum()/x.count())
.unstack()
.style
.format("{:.2%}")
)
'''
Date 2022-01-10 2022-02-10
Category
A 42.86% 60.00%
B 50.00% 50.00%
'''
这样我们就实现了需求。
(完)
更新时间:Aug. 18, 2024, 4:01 p.m. 标签:pandas 比例 格式