多输入输出geodataframe变量的函数并行化及存储方案咨询
问题1 解答:geodataframe并行化方案
你原来的写法报错不是geodataframe不可迭代,是进程池调用逻辑和参数传递方式不对:
- 不要在遍历geodataframe的循环内反复创建、关闭进程池,性能开销极高
starmap需要传入的是所有任务的参数元组组成的可迭代对象,不是单条任务的参数- 优先把参数提前提取成基础类型的列表,比直接传递pandas/geopandas对象序列化效率更高,也不容易出兼容性问题
可行的实现示例:
from multiprocessing import Pool import pandas as pd import geopandas as gpd def worker_1(pol_geom, xlon, ylat): # 替换为你自己的处理逻辑,返回处理好的GeoDataFrame即可 poly_gdf = gpd.GeoDataFrame({'geometry': [pol_geom]}, crs=gg.crs) point_gdf = gpd.GeoDataFrame( {'geometry': [gpd.points_from_xy([xlon], [ylat])[0]], 'lon':xlon, 'lat':ylat}, crs=gg.crs ) return poly_gdf, point_gdf if __name__ == '__main__': gg = gpd.read_file("name.shp") # 提前提取所有参数,组成参数元组列表 gg['centroid_x'] = gg.centroid.x gg['centroid_y'] = gg.centroid.y args_list = [(row.geometry, row.centroid_x, row.centroid_y) for _, row in gg.iterrows()] # 全局创建一次进程池,批量提交所有任务 with Pool() as pool: results = pool.starmap(worker_1, args_list) # 合并所有worker返回的结果 all_poly = gpd.GeoDataFrame(pd.concat([res[0] for res in results], ignore_index=True), crs=gg.crs) all_point = gpd.GeoDataFrame(pd.concat([res[1] for res in results], ignore_index=True), crs=gg.crs)
如果你不想自己写进程池逻辑,也可以直接用dask-geopandas的map_partitions接口,自动拆分geodataframe分区并行处理,代码更简洁。
问题2 解答:结果存储相关问题
- 压缩保存:geopandas的
to_file方法原生支持直接输出压缩包,只要把输出路径指定为.zip后缀即可,底层GDAL会自动打包:# 直接输出压缩后的shapefile压缩包 all_poly.to_file("polys.zip", driver="ESRI Shapefile", encoding="utf-8") - 多图层存储:shapefile格式本身不支持多图层,要单文件存多图层请使用GeoPackage(GPKG)格式,同一个gpkg文件可以写入多个图层,只需指定
layer参数即可:all_poly.to_file("result.gpkg", layer="polygons", driver="GPKG") all_point.to_file("result.gpkg", layer="points", driver="GPKG") - 不要用全局变量传递结果:多进程模式下每个进程会单独拷贝一份主进程的内存空间,子进程修改全局变量主进程感知不到,直接通过worker返回值传递结果即可,也可以在worker内直接写文件,注意给每个worker的输出文件加唯一标识避免写入冲突。
zip是内置的迭代器工具,支持接收任意可迭代对象作为输入(列表、元组、生成器、Series、GeoSeries都可以),输出的是按位置配对的元组迭代器,不是只能处理列表,你需要列表的话手动用list()转换即可。
内容的提问来源于stack exchange,提问作者user16708120
相关产品推荐
相关产品推荐

