Рекурсивное иерархическое объединение в Python DataFrame - PullRequest
0 голосов
/ 02 марта 2019

Я привык использовать 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-го уровня и т. Д.):

enter image description here

Мой рекурсивный код в 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 Ответ

0 голосов
/ 02 марта 2019

Вы могли бы сделать точечное отображение 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...