# 计算各类别产品销售额的三种占比
```
----------- 每篇一个pandas小技巧之三,分组数据计算各种占比
```
## 需求背景
**公司销售多种品牌的多种产品,现需要计算每个品牌下每种产品销售额的组内占比,组内累计占比和每组销售额占总销售的比例。以下列数据为例,简单解释这三种需求**
```
df
```
```
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
```
****
| | 销售日期 | 品牌 | 类别 | 款号 | 销量 |
| ---- | ------------ | ------ | -------- | ------ | ------ |
| 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 |
**
**
**从上述数据可以看出,该表记录的是每个品牌下每种产品在某日期的销售情况,以品牌A中的连衣裙为例:**
1. **计算每一天连衣裙的销售额占连衣裙总销售额的占比**
2. **计算每一天连衣裙的销售额占连衣裙总销售额的累计占比**
3. **计算品牌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;
}
```
****
| | 销售日期 | 品牌 | 类别 | 款号 | 销量 | 类别累计占比 |
| ---- | ------------ | ------ | -------- | ------ | ------ | -------------- |
| 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% |
**
**
**能看到,在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;
}
```
****
| | 销售日期 | 品牌 | 类别 | 款号 | 销量 | 类别累计占比 | 类别组内占比 |
| ---- | ------------ | ------ | -------- | ------ | ------ | -------------- | -------------- |
| 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% |
**