аналитика данных при построении иерархии
Решаю такую задачу:
В упрощенном виде: есть таблица следующего вида
| таб номер подч | подчиненный | таб номер рук | руководитель |
|---|---|---|---|
| 112233 | Ген. дер. | 123344456 | Вице-президент |
| 113213 | Гл. экономист | 112233 | Ген. дер. |
| 114213 | специалист | 112233 | Ген. дер. |
| 212233 | Слесарь | 12334 | Мастер |
| 353213 | Электрик | 12334 | Мастер |
| 12334 | Мастер | 45678 | Нач. цеха 1 |
| ... | ... | ... | ... |
и т.д.
Всего записей в таблице порядка 117 тыс. строк.
Так же есть таблица с расчетными показателями, наподобие этой (здесь показал именно структуру и наполнение таблицы, без отображения и пояснения сути значений в ней):
| таб номер сотрудника | причина отсутствия | число отгулов |
|---|---|---|
| 112233 | отпуск | 1 |
| 112233 | # | 0 |
| 123344456 | больничный | 0 |
| 113213 | обследование | 2 |
| 113213 | # | 0 |
| 113213 | прогул | 1 |
| 12334 | отпуск | 1 |
| 12334 | # | 0 |
| ... | ... | ... |
и т.д.
Мне необходимо вывести новую таблицу, в которой будут отражены только руководители и статистика по их команде с учетом самого руководителя. Команда - это подчиненные руководители и их сотрудники по иерархии вниз. То есть, для вице-президента должно отражаться количество подчиненных 4 (Вице-президент, Ген. дер., Гл. экономист, специалист), число отгулов 4. Примерно так:
| Руководитель | количество подчиненных | число отгулов по команде |
|---|---|---|
| 123344456 | 4 | 4 |
| 112233 | 3 | 4 |
| ... | ... | ... |
и т.д.
Уровень подчиненности для самих подчиненных я определяю следующим образом, используя такой код на Python:
# Функция для определения верхнеур. подчиненности
def find_top_leader(row):
leaders = []
while row['таб номер рук'] in df['таб номер подч'].values:
row = df[df['таб номер подч'] == row['таб номер рук']].iloc[0]
leaders.append(row['руководитель'])
return leaders
# Применяю функцию к каждой строке
df['верхнеур. подчиненность'] = df.apply(find_top_leader, axis=1)
# Создаю столбец с кортежами уровней подчиненности
df['уровни подчиненности'] = df['верхнеур. подчиненность'].apply(tuple)
# Разделяю кортежи на отдельные столбцы
df = pd.concat([df, df['уровни подчиненности'].apply(pd.Series).rename(lambda x: f'Уровень {x+1}', axis=1)], axis=1)
В итоге подчиненность с определением сотрудника и его вышестоящих руководителей выглядит так:
| таб номер подч | подчиненный | таб номер рук | руководитель | верхнеур. подчиненность |
|---|---|---|---|---|
| 112233 | Ген. дер. | 123344456 | Вице-президент | Вице-президент |
| 113213 | Гл. экономист | 112233 | Ген. дер. | Вице-президент |
| 114213 | специалист | 112233 | Ген. дер. | Вице-президент |
| 212233 | Слесарь | 12334 | Мастер | Нач. цеха 1 |
| 353213 | Электрик | 12334 | Мастер | Нач. цеха 1 |
| 12334 | Мастер | 45678 | Нач. цеха 1 | Нач. цеха 1 |
| ... | ... | ... | ... | ... |
и т.д.
Но у меня никак не выходит построить такую же таблицу только для руководителей с аккумулированием статистики по подчиненной команде. Буду благодарен за помощь.
Ответы (1 шт):
Если я правильно понял вопрос, то решение сводится к построению цепочек от руководителя к подчиненному (с помощью графа, например), а затем к элементарному подсчету нужных значений:
import networkx
from networkx.algorithms.components.connected import connected_components
import pandas as pd
l = pd.Series(zip(df["таб номер подч"], df["таб номер рук"])).values
def to_graph(l):
G = networkx.Graph()
for part in l:
G.add_nodes_from(part)
G.add_edges_from(to_edges(part))
return G
chains = to_graph(l)
chains = list(connected_components(chains))
print(chains)
выводим для наглядности список с цепочками:
[{123344456, 112233, 113213, 114213}, {212233, 45678, 353213, 12334}]
далее локатором выбираем нужные позиции из датафрейма
for chain in chains:
print(df.loc[df["таб номер подч"].isin(chain)])
получим датафреймы с нужными цепочками:
таб номер подч подчиненный таб номер рук руководитель
0 112233 Ген. дер. 123344456 Вице-президент
1 113213 Гл. экономист 112233 Ген. дер.
2 114213 специалист 112233 Ген. дер.
таб номер подч подчиненный таб номер рук руководитель
3 212233 Слесарь 12334 Мастер
4 353213 Электрик 12334 Мастер
5 12334 Мастер 45678 Нач. цеха 1
ну а дальше - получить данные из второй таблицы по табельным номерам первой.