需求背景
公司销售多种品牌的多种产品,现需要计算每个品牌下每种产品销售额的组内占比,组内累计占比和每组销售额占总销售的比例。以下列数据为例,简单解释这三种需求
df
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
|
销售日期 |
品牌 |
类别 |
款号 |
销量 |
|
|
0 |
2021-01-01 |
A |
T恤 |
1001 |
63 |
|
1 |
2021-01-02 |
A |
T恤 |
1002 |
21 |
|
2 |
2021-01-03 |
A |
T恤 |
1003 |
88 |
|
3 |
2021-01-04 |
B |
T恤 |
1004 |
88 |
|
4 |
2021-01-05 |
B |
T恤 |
1005 |
17 |
|
5 |
2021-01-06 |
B |
T恤 |
1006 |
98 |
|
6 |
2021-01-07 |
A |
T恤 |
1007 |
100 |
|
7 |
2021-01-08 |
A |
T恤 |
1008 |
95 |
|
8 |
2021-01-09 |
B |
T恤 |
1009 |
63 |
|
9 |
2021-01-10 |
B |
T恤 |
1010 |
86 |
|
10 |
2021-01-11 |
A |
裤子 |
1011 |
77 |
|
11 |
2021-01-12 |
A |
裤子 |
1012 |
81 |
|
12 |
2021-01-13 |
A |
连衣裙 |
1013 |
51 |
|
13 |
2021-01-14 |
A |
连衣裙 |
1014 |
93 |
|
14 |
2021-01-15 |
A |
裤子 |
1015 |
96 |
|
15 |
2021-01-16 |
A |
裤子 |
1016 |
39 |
|
16 |
2021-01-17 |
A |
连衣裙 |
1017 |
48 |
|
17 |
2021-01-18 |
A |
连衣裙 |
1018 |
98 |
|
18 |
2021-01-19 |
A |
连衣裙 |
1019 |
57 |
|
19 |
2021-01-20 |
B |
连衣裙 |
1020 |
12 |
|
20 |
2021-01-21 |
B |
连衣裙 |
1021 |
82 |
|
21 |
2021-01-22 |
B |
毛衣 |
1022 |
36 |
|
22 |
2021-01-23 |
B |
毛衣 |
1023 |
66 |
|
23 |
2021-01-24 |
B |
毛衣 |
1024 |
97 |
|
24 |
2021-01-25 |
B |
连衣裙 |
1025 |
72 |
|
25 |
2021-01-26 |
B |
连衣裙 |
1026 |
53 |
|
26 |
2021-01-27 |
B |
毛衣 |
1027 |
100 |
|
27 |
2021-01-28 |
B |
毛衣 |
1028 |
10 |
</div>
从上述数据可以看出,该表记录的是每个品牌下每种产品在某日期的销售情况,以品牌A中的连衣裙为例:
- 计算每一天连衣裙的销售额占连衣裙总销售额的占比
- 计算每一天连衣裙的销售额占连衣裙总销售额的累计占比
- 计算品牌A连衣裙的总销售额在所有产品总销售额中的占比
最终的表中,数据行数不变,每一条销售记录后边都添加上该条记录销售额的组内占比、组内累计占比和该品类销售额占所有产品销售额的比例。
首先,把原表中的数据按照品牌、类别和销量进行排序,其中品牌和类别是升序排序,销量降序排序。
不对销量排序也可以,这里为了效果明显,销量也进行了排序。
df1 = df.sort_values(["品牌","类别","销量"],ascending=[True,True,False])
#对原表按照品牌、类别、销量进行排序,其中品牌和类别升序排序,销量降序排序
组内累计占比
计算组内累计占比,首先按照品牌和类别进行分组,然后计算销量的累计和,用累计和除以分组后销量的总和即可。
计算过程中用到transform,前一篇文章里有介绍过transform的用法,这里不再赘述。
ss = df1.groupby(["品牌","类别"])["销量"].transform("cumsum")/df1.groupby(["品牌","类别"])["销量"].transform("sum")
# 按照品牌和类别分组,对分组后的数据按照分组求累计和,再对分组后的数据按照分组求和,两者相除得到组内累计占比,生成一个series
ss
6 0.272480
7 0.531335
2 0.771117
0 0.942779
1 1.000000
14 0.327645
11 0.604096
10 0.866894
15 1.000000
17 0.282421
13 0.550432
18 0.714697
12 0.861671
16 1.000000
5 0.278409
3 0.528409
9 0.772727
8 0.951705
4 1.000000
26 0.323625
23 0.637540
22 0.851133
21 0.967638
27 1.000000
20 0.374429
24 0.703196
25 0.945205
19 1.000000
Name: 销量, dtype: float64
计算的累计占比是series数据结构,其中的元素值都是浮点数,可以把浮点数转化成百分数。
注意在python中,数值型的数据中没有百分数这种数据类型,所以想要以百分数的形式展现,只能把浮点数转化成字符串,运用字符串的格式化方法。
具体代码和代码效果如下:
df1['类别累计占比'] = ss.apply(lambda x : format(x,'.2%'))
# 得到的累计占比是浮点数形式,修改成百分比形式
df1
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
|
销售日期 |
品牌 |
类别 |
款号 |
销量 |
类别累计占比 |
|
|
6 |
2021-01-07 |
A |
T恤 |
1007 |
100 |
27.25% |
|
7 |
2021-01-08 |
A |
T恤 |
1008 |
95 |
53.13% |
|
2 |
2021-01-03 |
A |
T恤 |
1003 |
88 |
77.11% |
|
0 |
2021-01-01 |
A |
T恤 |
1001 |
63 |
94.28% |
|
1 |
2021-01-02 |
A |
T恤 |
1002 |
21 |
100.00% |
|
14 |
2021-01-15 |
A |
裤子 |
1015 |
96 |
32.76% |
|
11 |
2021-01-12 |
A |
裤子 |
1012 |
81 |
60.41% |
|
10 |
2021-01-11 |
A |
裤子 |
1011 |
77 |
86.69% |
|
15 |
2021-01-16 |
A |
裤子 |
1016 |
39 |
100.00% |
|
17 |
2021-01-18 |
A |
连衣裙 |
1018 |
98 |
28.24% |
|
13 |
2021-01-14 |
A |
连衣裙 |
1014 |
93 |
55.04% |
|
18 |
2021-01-19 |
A |
连衣裙 |
1019 |
57 |
71.47% |
|
12 |
2021-01-13 |
A |
连衣裙 |
1013 |
51 |
86.17% |
|
16 |
2021-01-17 |
A |
连衣裙 |
1017 |
48 |
100.00% |
|
5 |
2021-01-06 |
B |
T恤 |
1006 |
98 |
27.84% |
|
3 |
2021-01-04 |
B |
T恤 |
1004 |
88 |
52.84% |
|
9 |
2021-01-10 |
B |
T恤 |
1010 |
86 |
77.27% |
|
8 |
2021-01-09 |
B |
T恤 |
1009 |
63 |
95.17% |
|
4 |
2021-01-05 |
B |
T恤 |
1005 |
17 |
100.00% |
|
26 |
2021-01-27 |
B |
毛衣 |
1027 |
100 |
32.36% |
|
23 |
2021-01-24 |
B |
毛衣 |
1024 |
97 |
63.75% |
|
22 |
2021-01-23 |
B |
毛衣 |
1023 |
66 |
85.11% |
|
21 |
2021-01-22 |
B |
毛衣 |
1022 |
36 |
96.76% |
|
27 |
2021-01-28 |
B |
毛衣 |
1028 |
10 |
100.00% |
|
20 |
2021-01-21 |
B |
连衣裙 |
1021 |
82 |
37.44% |
|
24 |
2021-01-25 |
B |
连衣裙 |
1025 |
72 |
70.32% |
|
25 |
2021-01-26 |
B |
连衣裙 |
1026 |
53 |
94.52% |
|
19 |
2021-01-20 |
B |
连衣裙 |
1020 |
12 |
100.00% |
</div>
能看到,在dataframe的最后多了一类累计占比。
前一篇的文章中我们已经讨论过组内占比的计算方法,这里我们可以再计算一遍,用来验证累计占比的结果是否正确
组内占比
组内占比计算方法前一篇文章已经讨论过,这里不再赘述,具体代码如下:
df1["类别组内占比"] = (df1["销量"]/df1.groupby(["品牌","类别"])["销量"].transform("sum")).apply(lambda x : format(x,'.2%'))
df1
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
|
销售日期 |
品牌 |
类别 |
款号 |
销量 |
类别累计占比 |
类别组内占比 |
|
|
6 |
2021-01-07 |
A |
T恤 |
1007 |
100 |
27.25% |
27.25% |
|
7 |
2021-01-08 |
A |
T恤 |
1008 |
95 |
53.13% |
25.89% |
|
2 |
2021-01-03 |
A |
T恤 |
1003 |
88 |
77.11% |
23.98% |
|
0 |
2021-01-01 |
A |
T恤 |
1001 |
63 |
94.28% |
17.17% |
|
1 |
2021-01-02 |
A |
T恤 |
1002 |
21 |
100.00% |
5.72% |
|
14 |
2021-01-15 |
A |
裤子 |
1015 |
96 |
32.76% |
32.76% |
|
11 |
2021-01-12 |
A |
裤子 |
1012 |
81 |
60.41% |
27.65% |
|
10 |
2021-01-11 |
A |
裤子 |
1011 |
77 |
86.69% |
26.28% |
|
15 |
2021-01-16 |
A |
裤子 |
1016 |
39 |
100.00% |
13.31% |
|
17 |
2021-01-18 |
A |
连衣裙 |
1018 |
98 |
28.24% |
28.24% |
|
13 |
2021-01-14 |
A |
连衣裙 |
1014 |
93 |
55.04% |
26.80% |
|
18 |
2021-01-19 |
A |
连衣裙 |
1019 |
57 |
71.47% |
16.43% |
|
12 |
2021-01-13 |
A |
连衣裙 |
1013 |
51 |
86.17% |
14.70% |
|
16 |
2021-01-17 |
A |
连衣裙 |
1017 |
48 |
100.00% |
13.83% |
|
5 |
2021-01-06 |
B |
T恤 |
1006 |
98 |
27.84% |
27.84% |
|
3 |
2021-01-04 |
B |
T恤 |
1004 |
88 |
52.84% |
25.00% |
|
9 |
2021-01-10 |
B |
T恤 |
1010 |
86 |
77.27% |
24.43% |
|
8 |
2021-01-09 |
B |
T恤 |
1009 |
63 |
95.17% |
17.90% |
|
4 |
2021-01-05 |
B |
T恤 |
1005 |
17 |
100.00% |
4.83% |
|
26 |
2021-01-27 |
B |
毛衣 |
1027 |
100 |
32.36% |
32.36% |
|
23 |
2021-01-24 |
B |
毛衣 |
1024 |
97 |
63.75% |
31.39% |
|
22 |
2021-01-23 |
B |
毛衣 |
1023 |
66 |
85.11% |
21.36% |
|
21 |
2021-01-22 |
B |
毛衣 |
1022 |
36 |
96.76% |
11.65% |
|
27 |
2021-01-28 |
B |
毛衣 |
1028 |
10 |
100.00% |
3.24% |
|
20 |
2021-01-21 |
B |
连衣裙 |
1021 |
82 |
37.44% |
37.44% |
|
24 |
2021-01-25 |
B |
连衣裙 |
1025 |
72 |
70.32% |
32.88% |
|
25 |
2021-01-26 |
B |
连衣裙 |
1026 |
53 |
94.52% |
24.20% |
|
19 |
2021-01-20 |
B |
连衣裙 |
1020 |
12 |
100.00% |
5.48% |
</div>
把组内占比的数据添加到累计占比后,很明显能够看出,我们累计占比的计算结果是正确的。
计算每个分组的销量占总销量的比例
计算每个分组的销售额占所有产品销售额的方法并不难,数据分组后求和,然后和所有产品销售额相除即可。
但是在当前问题中,我们希望让每一条销售记录后边都添加上该类产品销售额在总销售额中的占比,这里用到的也是transform。
这也是transform和apply两个方法之间的一个区别,要实现上述效果,apply做不到,因为apply输出汇总后的数据,两者的具体区别见如下代码:
df1.groupby(["品牌","类别"])["销量"].transform("sum")/df1["销量"].sum()
6 0.194489
7 0.194489
2 0.194489
0 0.194489
1 0.194489
14 0.155273
11 0.155273
10 0.155273
15 0.155273
17 0.183890
13 0.183890
18 0.183890
12 0.183890
16 0.183890
5 0.186539
3 0.186539
9 0.186539
8 0.186539
4 0.186539
26 0.163752
23 0.163752
22 0.163752
21 0.163752
27 0.163752
20 0.116057
24 0.116057
25 0.116057
19 0.116057
Name: 销量, dtype: float64
df1.groupby(["品牌","类别"])["销量"].apply(sum)/df1["销量"].sum()
品牌 类别
A T恤 0.194489
裤子 0.155273
连衣裙 0.183890
B T恤 0.186539
毛衣 0.163752
连衣裙 0.116057
Name: 销量, dtype: float64
apply也可以计算每个分组的销售额占总销售的比值,但是最终得到得的结果和原表中的数据量不匹配,无法添加到原表中,所以这里需要用transform方法,具体的代码如下:
(df1.groupby(["品牌","类别"])["销量"].transform("sum")/df1["销量"].sum()).apply(lambda x : format(x,'.2%'))
6 19.45%
7 19.45%
2 19.45%
0 19.45%
1 19.45%
14 15.53%
11 15.53%
10 15.53%
15 15.53%
17 18.39%
13 18.39%
18 18.39%
12 18.39%
16 18.39%
5 18.65%
3 18.65%
9 18.65%
8 18.65%
4 18.65%
26 16.38%
23 16.38%
22 16.38%
21 16.38%
27 16.38%
20 11.61%
24 11.61%
25 11.61%
19 11.61%
Name: 销量, dtype: object
df1["本组销量占比"] = (df1.groupby(["品牌","类别"])["销量"].transform("sum")/df1["销量"].sum()).apply(lambda x : format(x,'.2%'))
df1
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
|
销售日期 |
品牌 |
类别 |
款号 |
销量 |
类别累计占比 |
类别组内占比 |
本组销量占比 |
|
|
6 |
2021-01-07 |
A |
T恤 |
1007 |
100 |
27.25% |
27.25% |
19.45% |
|
7 |
2021-01-08 |
A |
T恤 |
1008 |
95 |
53.13% |
25.89% |
19.45% |
|
2 |
2021-01-03 |
A |
T恤 |
1003 |
88 |
77.11% |
23.98% |
19.45% |
|
0 |
2021-01-01 |
A |
T恤 |
1001 |
63 |
94.28% |
17.17% |
19.45% |
|
1 |
2021-01-02 |
A |
T恤 |
1002 |
21 |
100.00% |
5.72% |
19.45% |
|
14 |
2021-01-15 |
A |
裤子 |
1015 |
96 |
32.76% |
32.76% |
15.53% |
|
11 |
2021-01-12 |
A |
裤子 |
1012 |
81 |
60.41% |
27.65% |
15.53% |
|
10 |
2021-01-11 |
A |
裤子 |
1011 |
77 |
86.69% |
26.28% |
15.53% |
|
15 |
2021-01-16 |
A |
裤子 |
1016 |
39 |
100.00% |
13.31% |
15.53% |
|
17 |
2021-01-18 |
A |
连衣裙 |
1018 |
98 |
28.24% |
28.24% |
18.39% |
|
13 |
2021-01-14 |
A |
连衣裙 |
1014 |
93 |
55.04% |
26.80% |
18.39% |
|
18 |
2021-01-19 |
A |
连衣裙 |
1019 |
57 |
71.47% |
16.43% |
18.39% |
|
12 |
2021-01-13 |
A |
连衣裙 |
1013 |
51 |
86.17% |
14.70% |
18.39% |
|
16 |
2021-01-17 |
A |
连衣裙 |
1017 |
48 |
100.00% |
13.83% |
18.39% |
|
5 |
2021-01-06 |
B |
T恤 |
1006 |
98 |
27.84% |
27.84% |
18.65% |
|
3 |
2021-01-04 |
B |
T恤 |
1004 |
88 |
52.84% |
25.00% |
18.65% |
|
9 |
2021-01-10 |
B |
T恤 |
1010 |
86 |
77.27% |
24.43% |
18.65% |
|
8 |
2021-01-09 |
B |
T恤 |
1009 |
63 |
95.17% |
17.90% |
18.65% |
|
4 |
2021-01-05 |
B |
T恤 |
1005 |
17 |
100.00% |
4.83% |
18.65% |
|
26 |
2021-01-27 |
B |
毛衣 |
1027 |
100 |
32.36% |
32.36% |
16.38% |
|
23 |
2021-01-24 |
B |
毛衣 |
1024 |
97 |
63.75% |
31.39% |
16.38% |
|
22 |
2021-01-23 |
B |
毛衣 |
1023 |
66 |
85.11% |
21.36% |
16.38% |
|
21 |
2021-01-22 |
B |
毛衣 |
1022 |
36 |
96.76% |
11.65% |
16.38% |
|
27 |
2021-01-28 |
B |
毛衣 |
1028 |
10 |
100.00% |
3.24% |
16.38% |
|
20 |
2021-01-21 |
B |
连衣裙 |
1021 |
82 |
37.44% |
37.44% |
11.61% |
|
24 |
2021-01-25 |
B |
连衣裙 |
1025 |
72 |
70.32% |
32.88% |
11.61% |
|
25 |
2021-01-26 |
B |
连衣裙 |
1026 |
53 |
94.52% |
24.20% |
11.61% |
|
19 |
2021-01-20 |
B |
连衣裙 |
1020 |
12 |
100.00% |
5.48% |
11.61% |
</div>
从最终的结果表中,能够清楚的展现出每一笔销售额在组内的占比、累计占比以及本组销售额占总销售额的比例。
以上代码都不复杂,有不理解的地方或者不同意见欢迎留言讨论哦,