双图分区代码运行耗时过长,求问题原因与优化方案
初始分区耗时过长的原因及解决办法
核心原因分析
Updater定义错误
你在updaters中写的"connectedness": (nx.is_connected(hawaii_bl_dg))是直接计算整个图的连通性并赋值为布尔值,而非针对每个分区的连通性检查。这不仅逻辑错误,还可能在Partition初始化时引发不必要的无效计算。recursive_tree_part的低效调用
这是最主要的耗时原因:- 未指定
spanning_tree参数,导致函数每次尝试分区时都要为14000节点的图重新生成最小生成树(MST),该操作时间复杂度为O(n log n),反复执行会累积大量耗时。 - 参数传递存在歧义,你写的最后一个参数
10被当作max_tries,如果分区尝试不顺利,会重复执行MST生成和分区逻辑,进一步拉长耗时。
- 未指定
总人口计算的低效实现
使用for循环逐个节点累加人口,虽对14000节点来说耗时有限,但属于可优化的冗余操作。图结构的潜在问题
构建图时使用ignore_errors=True,可能导致图中存在孤立节点、无效边等异常结构,增加分区算法的复杂度和尝试次数。
具体解决办法
1. 修复连通性Updater
替换错误的连通性计算,使用Gerrychain内置的分区连通性检查工具:
from gerrychain.updaters import is_connected # 在updaters字典中修改: updaters={ "cut edges": cut_edges, "connectedness": is_connected, # 正确计算每个分区的连通性 "totpop": Tally("total", alias = "totpop"), "NHPIpop": Tally("other_nhpi", alias = "NHPIpop") }
2. 预生成最小生成树,优化分区函数调用
预先生成一次MST并传递给recursive_tree_part,避免重复生成:
# 预先生成最小生成树 spanning_tree = nx.minimum_spanning_tree(hawaii_bl_dg) # 调用recursive_tree_part时传入预生成的树 assignment = recursive_tree_part( hawaii_bl_dg, range(num_dist), ideal_pop, "total", 0.1, max_tries=10, # 明确参数名,避免歧义 spanning_tree=spanning_tree )
3. 优化总人口计算
用更高效的方式替代for循环:
# 直接从图节点属性求和 total_pop = sum(nx.get_node_attributes(hawaii_bl_dg, "total").values()) ideal_pop = total_pop / num_dist print("Ideal Pop:", ideal_pop)
4. 检查并修复图结构
去掉ignore_errors=True,先处理图的结构问题:
# 构建图时不忽略错误,先排查问题 hawaii_bl_dg = Graph.from_geodataframe(hawaii_bl) # 检查图是否连通,移除孤立节点(可选) if not nx.is_connected(hawaii_bl_dg): print("警告:图不连通,将移除孤立节点") hawaii_bl_dg.remove_nodes_from(list(nx.isolates(hawaii_bl_dg)))
5. 可选:调整分区参数
如果仍然耗时,可以尝试放宽人口偏差阈值(比如将epsilon从0.1调整为0.15),减少分区尝试的次数:
assignment = recursive_tree_part( hawaii_bl_dg, range(num_dist), ideal_pop, "total", 0.15, # 放宽到15%的人口偏差 max_tries=10, spanning_tree=spanning_tree )
内容的提问来源于stack exchange,提问作者Rina Nagashima
相关产品推荐
相关产品推荐

