该题目来自于力扣:
1731. 每位经理的下属员工数量 - 力扣(LeetCode)
题目要求:
表:Employees+-------------+----------+
| Column Name | Type |
+-------------+----------+
| employee_id | int |
| name | varchar |
| reports_to | int |
| age | int |
+-------------+----------+
employee_id 是这个表中具有不同值的列。
该表包含员工以及需要听取他们汇报的上级经理的 ID 的信息。 有些员工不需要向任何人汇报(reports_to 为空)。对于此问题,我们将至少有一个其他员工需要向他汇报的员工,视为一个经理。编写一个解决方案来返回需要听取汇报的所有经理的 ID、名称、直接向该经理汇报的员工人数,以及这些员工的平均年龄,其中该平均年龄需要四舍五入到最接近的整数。返回的结果集需要按照 employee_id 进行排序。结果的格式如下:示例 1:输入:
Employees 表:
+-------------+---------+------------+-----+
| employee_id | name | reports_to | age |
+-------------+---------+------------+-----+
| 9 | Hercy | null | 43 |
| 6 | Alice | 9 | 41 |
| 4 | Bob | 9 | 36 |
| 2 | Winston | null | 37 |
+-------------+---------+------------+-----+
输出:
+-------------+-------+---------------+-------------+
| employee_id | name | reports_count | average_age |
+-------------+-------+---------------+-------------+
| 9 | Hercy | 2 | 39 |
+-------------+-------+---------------+-------------+
解释:
Hercy 有两个需要向他汇报的员工, 他们是 Alice and Bob. 他们的平均年龄是 (41+36)/2 = 38.5, 四舍五入的结果是 39.
示例 2:输入:
Employees 表:
+-------------+---------+------------+-----+
| employee_id | name | reports_to | age |
|-------------|---------|------------|-----|
| 1 | Michael | null | 45 |
| 2 | Alice | 1 | 38 |
| 3 | Bob | 1 | 42 |
| 4 | Charlie | 2 | 34 |
| 5 | David | 2 | 40 |
| 6 | Eve | 3 | 37 |
| 7 | Frank | null | 50 |
| 8 | Grace | null | 48 |
+-------------+---------+------------+-----+
输出:
+-------------+---------+---------------+-------------+
| employee_id | name | reports_count | average_age |
| ----------- | ------- | ------------- | ----------- |
| 1 | Michael | 2 | 40 |
| 2 | Alice | 2 | 37 |
| 3 | Bob | 1 | 37 |
+-------------+---------+---------------+-------------+
思路流程:
首先它要求返回员工的统计数量和年龄聚合,我们可以提前把聚合函数写出来,在考虑表的连接。利用reports_to列进行分组,保留所有有老板的员工,再用agg函数对员工的数量和年龄的平均进行聚合,这里我叫它表A。在分组聚合后,我们发现,表A中的reports_to列和原表格的employee_id列相符(经理的名字也在雇员列中),我们可以想到左右的指定键连接。保留表A的所有数据,将表A的reports_to列和源数据的employee_id列进行左右连接,即可实现要求。
代码实现:
1)进行分组聚合和重命名
import pandas as pddef count_employees(employees: pd.DataFrame) -> pd.DataFrame:a=employees.groupby('reports_to').agg({'employee_id':'count','age':'mean'}).rename(columns={'age':'average_age','employee_id':'reports_count'}).reset_index()return a
这里我们实现了人数的聚合和年龄平均的计算,由于分组的参数是reports_to列,它会被作为内索引,为后续操作更明了,我使用了reset_index()来将该列显示了出来。
| reports_to | reports_count | average_age |
| ---------- | ------------- | ----------- |
| 9 | 2 | 38.5 |
可见保留了三列:reports_to列,重命名后的age列和employee_id列
2)进行左右指定键的连接
import pandas as pddef count_employees(employees: pd.DataFrame) -> pd.DataFrame:a=employees.groupby('reports_to').agg({'employee_id':'count','age':'mean'}).rename(columns={'age':'average_age','employee_id':'reports_count'}).reset_index() a=a.merge(employees,how='left',left_on='reports_to',right_on='employee_id')return a
这里我们用左连接(表A在左边)完全保留表A的所有数据,之后用left_on和right_on来让表A的reports_to列和原表格的employee_id进行连接,这样就可以找出包含下属员工的数量,下属员工的平均年龄,以及经理的年龄和ID的列了
| reports_to_x | reports_count | average_age | employee_id | name | reports_to_y | age |
| ------------ | ------------- | ----------- | ----------- | ----- | ------------ | --- |
| 9 | 2 | 38.5 | 9 | Hercy | null | 43 |
可见所有的数据此时都完全聚合到了一块,我们最难的任务也就基本完成了,接下来就需要我们取出并且变形我们需要的列,再把他们展示出来即可。
3)平均年龄的四舍五入需求
我们遇到一个很棘手的问题,要把平均年龄进行四舍五入,用后缀.round(0)肯定是不行的,它只会把小数点后的所有数据到消除,那么如何实现呢?用int可以,int也会取整,但如果小数位大于5的数据再加一个0.5,那么它的整数为肯定会进一;如果小数位小于5的数据再加一个0.5,那么它的整数位不会进一,这时候再用int进行取整就会实现四舍五入了。利用apply(lambda x:int(x+.05))即可遍历实现四舍五入的要求:
import pandas as pddef count_employees(employees: pd.DataFrame) -> pd.DataFrame:a=employees.groupby('reports_to').agg({'employee_id':'count','age':'mean'}).rename(columns={'age':'average_age','employee_id':'reports_count'}).reset_index()a=a.merge(employees,how='left',left_on='reports_to',right_on='employee_id')a['average_age']=a['average_age'].apply(lambda x:int(x+0.5))return a[['employee_id','name','reports_count','average_age']]
总结:
该题目难在我们可能不会想到左右的指定键位连接,从而使进程陷入停滞。还是要多加练习,把各种连接内化于心,才可以更从容的面对更多复杂的需求