基于Python Pandas DataFrame并行化逆地理编码函数的实现需求
嘿,我来帮你搞定这个并行逆地理编码的需求!咱们一步步来,从选工具到写代码,再到避坑提示都安排得明明白白。
第一步:准备依赖库
首先得装好用的逆地理编码工具,这里推荐用geopy(免费且易用),再加上你已经在用的pandas:
pip install geopy pandas
multiprocessing是Python标准库,不用额外安装。
第二步:写单个经纬度的逆地理编码函数
先写一个处理单组经纬度的核心函数,要考虑请求失败、地址字段兼容这些细节:
from geopy.geocoders import Nominatim from geopy.exc import GeocoderTimedOut, GeocoderUnavailable import time def get_city_from_coords(lat_lon): # 必须设置user_agent,不然Nominatim会拒绝请求(随便填个你的应用名就行) geolocator = Nominatim(user_agent="my_city_geocoder") lat, lon = lat_lon try: # 逆地理编码,指定返回地址详情,方便提取城市 location = geolocator.reverse((lat, lon), exactly_one=True, addressdetails=True) if not location: return None # 不同地区的地址字段可能不同,多做几个备选兼容 address = location.raw['address'] city = ( address.get('city') or address.get('town') or address.get('municipality') or address.get('village') or None ) return city except (GeocoderTimedOut, GeocoderUnavailable): # 网络超时或服务不可用时,重试一次(加个延迟避免频繁请求) time.sleep(2) return get_city_from_coords(lat_lon) except Exception as e: print(f"处理经纬度({lat}, {lon})时出错: {str(e)}") return None
关键细节:
- 每个进程单独初始化
Nominatim对象,避免进程间的资源冲突 - 兼容不同地区的地址字段(比如国内城市用
city,小镇可能用town) - 加重试机制应对网络波动
第三步:用multiprocessing实现并行处理
接下来把你的numpy经纬度数组转成可迭代的元组列表,再用进程池并行处理:
import pandas as pd import numpy as np from multiprocessing import Pool if __name__ == "__main__": # 假设你已经有了包含经纬度的DataFrame(替换成你的实际df) df = pd.DataFrame({ 'latitude': [39.9042, 31.2304, 23.1291], 'longitude': [116.4074, 121.4737, 113.2644] }) # 你已经切片好的numpy数组(直接用你自己的coords_array就行) coords_array = df[['latitude', 'longitude']].to_numpy() # 转成元组列表,方便multiprocessing的map处理 coords_list = list(map(tuple, coords_array)) # 设置进程数:别贪多!Nominatim免费版限制每秒1次请求,建议设4-8个 num_processes = 4 # 创建进程池并行处理 with Pool(num_processes) as pool: city_results = pool.map(get_city_from_coords, coords_list) # 把结果赋值给city列 df['city'] = city_results # 可选:填充无法解析的空值 df['city'] = df['city'].fillna('未知城市') # 查看最终结果 print(df)
Windows用户注意:必须把主逻辑放在if __name__ == "__main__":块里,不然会触发multiprocessing的重复进程创建bug。
第四步:避坑关键提示
- Nominatim请求限制:免费版严格限制每秒1次请求,如果进程数太多,会被临时封禁IP。要么降低进程数,要么在
get_city_from_coords函数末尾加time.sleep(1)强制延迟。 - 数据量太大?用imap加进度条:如果你的经纬度数据有上万条,可以用
tqdm显示处理进度:from tqdm import tqdm with Pool(num_processes) as pool: city_results = list(tqdm(pool.imap(get_city_from_coords, coords_list), total=len(coords_list))) - 隐私与合规:如果是商业用途,建议用付费的逆地理编码服务(比如高德、百度地图的API),免费的Nominatim有使用限制,且数据更新可能不及时。
内容的提问来源于stack exchange,提问作者addictedtohaskell
相关产品推荐
相关产品推荐

