如何优化Python实现的地址偏远度计算算法以提升运行效率
性能优化可从以下几个核心环节入手,按收益从高到低排序:
1. 彻底替换纯Python内层循环为numpy向量化运算
你当前代码里for j in range(ZONES)逐点计算距离的逻辑是最大的性能瓶颈,完全没有用到numpy的批量运算优势,所有距离计算可以一次性完成,无需循环。
首先做一次全局预处理,把所有片区的经纬度提前转成弧度,避免每次循环重复计算:
# 预处理仅执行一次 zone_lat_rad = np.radians(zonematrix[:, 0]) zone_lon_rad = np.radians(zonematrix[:, 1]) zone_pop = zonematrix[:, 2]
然后每个地址的距离计算直接批量完成:
addr_lat_rad = np.radians(address["x"]) addr_lon_rad = np.radians(address["y"]) dlat = zone_lat_rad - addr_lat_rad dlon = zone_lon_rad - addr_lon_rad a = np.sin(dlat/2)**2 + np.cos(addr_lat_rad) * np.cos(zone_lat_rad) * np.sin(dlon/2)**2 distances = 6371000 * 2 * np.arctan2(np.sqrt(a), np.sqrt(1-a))
这一步优化至少能带来10倍以上的性能提升。
2. 优化多半径统计逻辑,避免重复遍历
你当前对每个半径都单独做布尔索引筛选,属于重复计算。可以先把距离排序后用前缀和+二分查找快速统计:
# 距离和对应人口排序,预计算人口前缀和 sorted_idx = np.argsort(distances) sorted_dist = distances[sorted_idx] pop_cumsum = np.cumsum(zone_pop[sorted_idx]) index = 0 for radius in RADII: # 二分查找直接得到当前半径内的片区数量,无需遍历 cnt = np.searchsorted(sorted_dist, radius, side='right') if cnt == 0: factor = 0 else: factor = pop_cumsum[cnt-1] / cnt index += factor / radius
这一步能把统计环节的耗时降低70%以上。
3. 移除冗余操作
- 不需要单独维护带人口的distances矩阵,人口是全局固定值,提前存在单独的数组即可,无需每次循环重复赋值
- 所有固定的角度转换、常数计算全部提前预处理,不要放到循环内执行
4. 进阶优化方案
如果优化完前三点还达不到性能要求,可以继续做以下优化:
- 给片区中心建空间索引(比如KD树、R树),最大半径只有16280米,每次只需要计算地址周边16公里范围内的片区即可,不用和所有片区算距离,片区量级大的情况下收益极高,可以用
scipy.spatial.KDTree实现 - 用
numba的@njit装饰器编译核心计算逻辑,不用换编程语言就能获得接近C语言的性能 - 批量处理地址,一次性计算一批地址到所有片区的距离,进一步发挥numpy的批量运算优势
关于换编程语言
不需要第一时间换语言,做完前三点优化性能至少能提升2050倍,原来23秒跑5000条,优化后不到1秒就能跑完,500万条数据全量跑只需要12小时,完全满足需求。如果还有更高性能要求,再考虑用C++/Rust重写核心逻辑即可。
内容的提问来源于stack exchange,提问作者Jacky
相关产品推荐
相关产品推荐

