#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
Я привык использовать SQL для решения иерархических объединений, но мне интересно, можно ли это сделать на Python, возможно, с помощью Pandas. И какой из них более эффективен?
Данные CSV: emp_id,fn,ln,mgr_id
1,Matthew,Reichek,NULL
2,John,Cottone,3
3,Chris,Winter,1
4,Sergey,Bobkov,2
5,Andrey,Botelli,2
6,Karen,Goetz,7
7,Tri,Pham,3
8,Drew,Thompson,7
9,BD,Alabi,7
10,Sreedhar,Kavali,7
Я хочу найти уровень каждого сотрудника (босс — уровень 1 и так далее):
Мой рекурсивный код в SQL был бы:
with recursive cte as
(
select employee_id, first_name, last_name, manager_id, 1 as level
from icqa.employee
where manager_id is null
union
select e.employee_id, e.first_name, e.last_name, e.manager_id, cte.level 1
from icqa.employee e
inner join cte
on e.manager_id = cte.employee_id
where e.manager_id is not null
)
select * from cte
Комментарии:
1. можете ли вы кратко объяснить логику поиска уровня?
2. Мы находим уровень, определяя, кто является менеджером каждого сотрудника. У БОССА нет менеджера, поэтому уровень 1. тогда те, кто отчитывается перед Боссом, будут уровня 2, затем следующий уровень будет 3 и так далее.
Ответ №1:
Вы могли бы создать отображение dict emp_id
в mgr_id
, а затем создать рекурсивную функцию типа
idmap = dict(zip(df['emp_id'], df['mgr_id']))
def depth(id_):
if np.isnan(id_):
return 1
return depth(idmap[id_]) 1
для вычисления глубины задается id
.
Чтобы сделать его более эффективным (не повторяя вычисления для одного и того же id
),
вы могли бы использовать запоминание (обрабатывается @functools.lru_cache
декоратором ниже):
import numpy as np
import pandas as pd
import functools
nan = np.nan
df = pd.DataFrame({'emp_id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'fn': ['Matthew', 'John', 'Chris', 'Sergey', 'Andrey', 'Karen', 'Tri', 'Drew', 'BD', 'Sreedhar'], 'ln': ['Reichek', 'Cottone', 'Winter', 'Bobkov', 'Botelli', 'Goetz', 'Pham', 'Thompson', 'Alabi', 'Kavali'], 'mgr_id': [nan, 3.0, 1.0, 2.0, 2.0, 7.0, 3.0, 7.0, 7.0, 7.0]})
def make_depth(df):
idmap = dict(zip(df['emp_id'], df['mgr_id']))
@functools.lru_cache()
def depth(id_):
if np.isnan(id_):
return 1
return depth(idmap[id_]) 1
return depth
df['depth'] = df['mgr_id'].apply(make_depth(df))
print(df.sort_values(by='depth'))
выдает
emp_id fn ln mgr_id depth
0 1 Matthew Reichek NaN 1
2 3 Chris Winter 1.0 2
1 2 John Cottone 3.0 3
6 7 Tri Pham 3.0 3
3 4 Sergey Bobkov 2.0 4
4 5 Andrey Botelli 2.0 4
5 6 Karen Goetz 7.0 4
7 8 Drew Thompson 7.0 4
8 9 BD Alabi 7.0 4
9 10 Sreedhar Kavali 7.0 4