Решение Скотта Бостона Networkx является предпочтительным решением ...
Есть два решения этой проблемы.Первый - векторизованное решение типа pandas, и он должен быть быстрым для больших наборов данных, второй - питоническим и не очень хорошо работает с размером набора данных, который искал OP, исходный размер df (223635,4).
- PANDAS SOLUTION
Эта задача состоит в том, чтобы выяснить, сколько людей управляет каждый человек в организации, включая подчиненных.Это решение создаст информационный фрейм, добавив последующие столбцы, являющиеся менеджерами предыдущих столбцов, а затем подсчитав количество сотрудников в этом фрейме, чтобы определить общее число под ними.
Сначала мы настроим вход.
import pandas as pd
import numpy as np
data = [
["John", "144", "Smith", "200"],
["Mia", "220", "John", "144"],
["Caleb", "155", "Smith", "200"],
["Smith", "200", "Jason", "500"],
]
df = pd.DataFrame(data, columns=["Name", "SID", "Manager_name", "Manager_SID"])
df = df[["SID", "Manager_SID"]]
# shortening the columns for convenience
df.columns = ["1", "2"]
print(df)
1 2
0 144 200
1 220 144
2 155 200
3 200 500
Сначала необходимо подсчитать сотрудников без подчиненных и поместить их в отдельный словарь.
df_not_mngr = df.loc[~df['1'].isin(df['2']), '1']
non_mngr_dict = {str(key):0 for key in df_not_mngr.values}
non_mngr_dict
{'220': 0, '155': 0}
Далее мы изменим кадр данных, добавив столбцы менеджеров предыдущего столбца.Цикл останавливается, когда в самом правом столбце нет сотрудников
for i in range(2, 10):
df = df.merge(
df[["1", "2"]], how="left", left_on=str(i), right_on="1", suffixes=("_l", "_r")
).drop("1_r", axis=1)
df.columns = [str(x) for x in range(1, i + 2)]
if df.iloc[:, -1].isnull().all():
break
else:
continue
print(df)
1 2 3 4 5
0 144 200 500 NaN NaN
1 220 144 200 500 NaN
2 155 200 500 NaN NaN
3 200 500 NaN NaN NaN
Все столбцы, кроме первых столбцов, свернуты, а каждый сотрудник подсчитан и добавлен в словарь.
from collections import Counter
result = dict(Counter(df.iloc[:, 1:].values.flatten()))
К результату добавляется словарь без менеджера.
result.update(non_mngr_dict)
result
{'200': 3, '500': 4, nan: 8, '144': 1, '220': 0, '155': 0}
РЕКУРСИВНОЕ ПИТОНИЧЕСКОЕ РЕШЕНИЕ
Я думаю, что это, вероятно, гораздо более питон, чем вы искали.Сначала я создал список all_sids, чтобы убедиться, что мы фиксируем всех сотрудников, поскольку не все присутствуют в каждом списке.
import pandas as pd
import numpy as np
data = [
["John", "144", "Smith", "200"],
["Mia", "220", "John", "144"],
["Caleb", "155", "Smith", "200"],
["Smith", "200", "Jason", "500"],
]
df = pd.DataFrame(data, columns=["Name", "SID", "Manager_name", "Manager_SID"])
all_sids = pd.unique(df[['SID', 'Manager_SID']].values.ravel('K'))
Затем создайте сводную таблицу.
dfp = df.pivot_table(values='Name', index='SID', columns='Manager_SID', aggfunc='count')
dfp
Manager_SID 144 200 500
SID
144 NaN 1.0 NaN
155 NaN 1.0 NaN
200 NaN NaN 1.0
220 1.0 NaN NaN
Затем функция, которая будет проходить через сводную таблицу для суммирования всех отчетов..
def count_mngrs(SID, count=0):
if str(SID) not in dfp.columns:
return count
else:
count += dfp[str(SID)].sum()
sid_list = dfp[dfp[str(SID)].notnull()].index
for sid in sid_list:
count = count_mngrs(sid, count)
return count
Вызовите функцию для каждого сотрудника и распечатайте результаты.
print('SID', ' Number of People Reporting')
for sid in all_sids:
print(sid, " " , int(count_mngrs(sid)))
Результаты приведены ниже, извините, я немного ленив в добавлении имен с помощью sids.
SID Number of People Reporting
144 1
220 0
155 0
200 3
500 4
С нетерпением ждем возможности найти более подходящее решение для панд!