# 计算每个销售小组每个成员销售业绩占比及组内排名
```
----------- 每篇一个pandas小技巧之二,分组数据计算组内占比及排序
```
**文中代码使用的pandas版本1.3.2**
## 需求背景:
**某公司有若干销售小组,现有所有销售人员某月的销售额,现需要计算每位成员的销售额占本组总销售额的比例,并且计算每位成员在本组内销售额的排名。**
**为了便于更直观的查看代码效果,从所有数据中截取一小部分数据作为示例。**
**原始数据如下:**
```
df
```
```
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
```
****
| 序号 | 姓名 | 组别 | 销售额 |
| ---- | ------ | ----- | ------ |
| 17 | 王右江 | 第1组 | 69 |
| 18 | 吴东飞 | 第1组 | 14 |
| 19 | 张中名 | 第4组 | 97 |
| 20 | 李左河 | 第4组 | 27 |
| 21 | 常一名 | 第2组 | 83 |
| 22 | 吴上江 | 第1组 | 65 |
| 23 | 张中海 | 第1组 | 29 |
| 24 | 张二海 | 第2组 | 10 |
| 25 | 李南河 | 第2组 | 29 |
| 26 | 蔡北江 | 第4组 | 32 |
| 27 | 王上河 | 第4组 | 72 |
| 28 | 张东名 | 第4组 | 76 |
| 29 | 蔡右海 | 第2组 | 47 |
| 30 | 梁二海 | 第1组 | 56 |
| 31 | 梁东名 | 第2组 | 43 |
**
**
**查看数据中一共有几个分组以及每个分组中有几位员工,代码如下:**
```
df["组别"].value_counts()
```
```
第1组 5
第4组 5
第2组 5
Name: 组别, dtype: int64
```
## 计算组内占比
**截取的数据中一共包含三个小组,每个小组分别有5位员工。**
**以这部分数据为例,计算每位员工的销售额占本组总销售额的占比。用到的具体代码如下:**
```
df.groupby("组别")["销售额"].transform(lambda x:x/x.sum())
```
```
序号
17 0.296137
18 0.060086
19 0.319079
20 0.088816
21 0.391509
22 0.278970
23 0.124464
24 0.047170
25 0.136792
26 0.105263
27 0.236842
28 0.250000
29 0.221698
30 0.240343
31 0.202830
Name: 销售额, dtype: float64
```
**groupby对象的transform方法和apply方法类似,接收的参数都是函数,都是用分组后每组的dataframe作为传递给transform或者apply的函数的参数。**
**如上述代码汇总,就是把每个分组的dataframe作为参数传递给了lambda函数,而lambda函数的作用是计算每个销售额与组内总销售额的比值,得到的即为每位员工销售额占组内总销售额的占比。**
**把上述代码计算出的结果添加到原表当中去,代码如下:**
```
df["组内占比"] = df.groupby("组别")["销售额"].transform(lambda x:x/x.sum())
```
**下表为添加后的结果展示:**
```
df
```
```
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
```
****
| 序号 | 姓名 | 组别 | 销售额 | 组内占比 |
| ---- | ------ | ----- | ------ | -------- |
| 17 | 王右江 | 第1组 | 69 | 0.296137 |
| 18 | 吴东飞 | 第1组 | 14 | 0.060086 |
| 19 | 张中名 | 第4组 | 97 | 0.319079 |
| 20 | 李左河 | 第4组 | 27 | 0.088816 |
| 21 | 常一名 | 第2组 | 83 | 0.391509 |
| 22 | 吴上江 | 第1组 | 65 | 0.278970 |
| 23 | 张中海 | 第1组 | 29 | 0.124464 |
| 24 | 张二海 | 第2组 | 10 | 0.047170 |
| 25 | 李南河 | 第2组 | 29 | 0.136792 |
| 26 | 蔡北江 | 第4组 | 32 | 0.105263 |
| 27 | 王上河 | 第4组 | 72 | 0.236842 |
| 28 | 张东名 | 第4组 | 76 | 0.250000 |
| 29 | 蔡右海 | 第2组 | 47 | 0.221698 |
| 30 | 梁二海 | 第1组 | 56 | 0.240343 |
| 31 | 梁东名 | 第2组 | 43 | 0.202830 |
**
**
**如果希望“组内占比”列的数据展现形式是百分数的形式,可以用字符串的格式化对数据格式进行修改。需要注意修改后的数据不再是数值型,而是字符串,不能再进行聚合运算,所以转换的时候要慎重。转换的代码如下:**
```
df["组内占比"].apply(lambda x:"{:.2%}".format(x))
```
```
序号
17 29.61%
18 6.01%
19 31.91%
20 8.88%
21 39.15%
22 27.90%
23 12.45%
24 4.72%
25 13.68%
26 10.53%
27 23.68%
28 25.00%
29 22.17%
30 24.03%
31 20.28%
Name: 组内占比, dtype: object
```
## 计算组内排名
**计算组内排名,需要用到groupby对象的rank方法,该方法是专门计算排名的方法。依据哪一列计算排名,就用groupby对象的哪一列调用该方法即可。**
**接前边的例子,要计算每位员工的销售额在组内的排名,只需要按照“组别”列进行分组,然后按照“销售额”列进行排名即可,新增排名列,排名数据添加到原表中,代码如下:**
```
df["组内排名"] = df.groupby("组别")["销售额"].rank(ascending=False).astype(int) #ascending=False表示降序排序进行排名
#由于排名后的数据类型是浮点型,用astype方法修改数据类型为整型
```
**注意,rank排名的方式分好几种,有时候排名会出现0.5,所以不是每次排名的结果都可以转换成整型,详情见文章最后,对rank排名方式汇总的代码结果中有展现。**
**查看添加排名数据后的df表:**
```
df
```
```
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
```
****
| 序号 | 姓名 | 组别 | 销售额 | 组内占比 | 组内排名 |
| ---- | ------ | ----- | ------ | -------- | -------- |
| 17 | 王右江 | 第1组 | 69 | 0.296137 | 1 |
| 18 | 吴东飞 | 第1组 | 14 | 0.060086 | 5 |
| 19 | 张中名 | 第4组 | 97 | 0.319079 | 1 |
| 20 | 李左河 | 第4组 | 27 | 0.088816 | 5 |
| 21 | 常一名 | 第2组 | 83 | 0.391509 | 1 |
| 22 | 吴上江 | 第1组 | 65 | 0.278970 | 2 |
| 23 | 张中海 | 第1组 | 29 | 0.124464 | 4 |
| 24 | 张二海 | 第2组 | 10 | 0.047170 | 5 |
| 25 | 李南河 | 第2组 | 29 | 0.136792 | 4 |
| 26 | 蔡北江 | 第4组 | 32 | 0.105263 | 4 |
| 27 | 王上河 | 第4组 | 72 | 0.236842 | 3 |
| 28 | 张东名 | 第4组 | 76 | 0.250000 | 2 |
| 29 | 蔡右海 | 第2组 | 47 | 0.221698 | 2 |
| 30 | 梁二海 | 第1组 | 56 | 0.240343 | 3 |
| 31 | 梁东名 | 第2组 | 43 | 0.202830 | 3 |
**
**
**提取其中一个分组,查看排名结果,如下:**
```
df.groupby("组别").get_group("第1组")
```
```
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
```
****
| 序号 | 姓名 | 组别 | 销售额 | 组内占比 | 组内排名 |
| ---- | ------ | ----- | ------ | -------- | -------- |
| 17 | 王右江 | 第1组 | 69 | 0.296137 | 1 |
| 18 | 吴东飞 | 第1组 | 14 | 0.060086 | 5 |
| 22 | 吴上江 | 第1组 | 65 | 0.278970 | 2 |
| 23 | 张中海 | 第1组 | 29 | 0.124464 | 4 |
| 30 | 梁二海 | 第1组 | 56 | 0.240343 | 3 |
****
**rank方法的常用参数除了ascending用来指定排序方向之外,还有另一个常用参数method,即排名的方式,假如上述例子中,有两个人的销售额一样,比如都是排名第二,那么允许有并列第二,还是不允许有并列情况出现;如果允许有并列情况出现,那么,下一个名次人的排名是第三还是第四?method参数就是解决这些问题,具体的参数详情见下边官网的例子:**
```
df1 = pd.DataFrame({ "group": ["a", "a", "a", "a", "a", "b", "b", "b", "b", "b"], "value": [2, 4, 2, 3, 5, 1, 2, 4, 1, 5],})
df1
```
```
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
```
****
|