如何大幅提升NetworkX生成177K条数据管理层级的性能
优化百万级员工管理层级生成效率的方案
问题背景
现有员工-经理关系数据集示例:
Emp Mgr 0 E1 M1 1 M1 M2 2 M3 M5 3 M2 M5
需要为每位员工生成从最高层管理者到自身的层级序列,输出格式示例:
Emp Mgr Level_01 Level_02 Level_03 Level_04 0 E1 M1 M5 M2 M1 E1 1 M1 M2 M5 M2 M1 2 M3 M5 M5 M3 3 M2 M5 M5 M2
当前使用NetworkX的方案在177K条记录、2个根节点的数据集上耗时超6小时,需大幅优化运行速度。
原方案低效原因
原方案中nx.all_simple_paths会遍历节点间的所有可能路径再筛选第一条,对于大型树形结构的图来说,会产生大量不必要的计算;同时逐行遍历员工节点生成路径的方式,未利用批量处理优势,导致整体时间复杂度极高。
优化方案
方案1:迭代式向上追溯(最优选择,适合树/森林结构)
员工层级本质是树形结构(每个员工仅有一个直属经理),可直接迭代向上追溯上级,结合缓存避免重复计算,时间复杂度接近O(N):
import pandas as pd # 构建员工到直属经理的快速映射 emp_to_mgr = df.set_index('Emp')['Mgr'].to_dict() # 缓存已计算的层级路径,避免重复遍历上级 path_cache = {} def get_full_hierarchy(emp): if emp in path_cache: return path_cache[emp] # 从员工自身开始向上追溯 hierarchy = [emp] current = emp while current in emp_to_mgr: current = emp_to_mgr[current] hierarchy.append(current) # 反转顺序,得到从最高层到员工的序列 hierarchy = hierarchy[::-1] path_cache[emp] = hierarchy return hierarchy # 批量生成所有员工的层级数据 level_records = [get_full_hierarchy(emp) for emp in df['Emp']] # 转换为标准化的层级DataFrame max_level_count = max(len(rec) for rec in level_records) level_df = pd.DataFrame(level_records, index=df.index).fillna('') level_df.columns = [f'Level_{i+1:02d}' for i in range(max_level_count)] # 合并原始数据与层级数据 final_result = pd.concat([df, level_df], axis=1)
该方案通过缓存复用上级路径(如同一经理的所有下属共享相同的上级序列),避免大量重复计算,在177K数据量下可在几分钟甚至更短时间内完成。
方案2:NetworkX优化(保留图框架的次优选择)
若必须使用NetworkX,可改用nx.shortest_path一次性计算根节点到所有下属的路径,替代低效的all_simple_paths:
import networkx as nx import pandas as pd # 构建有向图 G = nx.from_pandas_edgelist(df, source='Mgr', target='Emp', create_using=nx.DiGraph) # 定位根节点(无上级的最高管理者) roots = [n for n, d in G.in_degree() if d == 0] # 预计算所有根节点到下属的最短路径(树形结构中即唯一路径) all_paths = {} for root in roots: all_paths.update(nx.shortest_path(G, source=root)) # 提取每个员工的层级路径 level_records = [all_paths.get(emp, []) for emp in df['Emp']] # 后续格式处理同方案1 max_level_count = max(len(rec) for rec in level_records) level_df = pd.DataFrame(level_records, index=df.index).fillna('') level_df.columns = [f'Level_{i+1:02d}' for i in range(max_level_count)] final_result = pd.concat([df, level_df], axis=1)
该方案通过批量计算路径避免了逐节点遍历图的低效操作,运行速度比原方案提升数十倍。
内容的提问来源于stack exchange,提问作者priya
相关产品推荐
相关产品推荐

