遍历Pandas DataFrame用geopy逆地理编码获州信息遇错求助
问题解决
第一个错误:ValueError: Must be a coordinate pair or Point
你的遍历逻辑完全错误,for row in df 遍历的是DataFrame的列名,不是每一行数据。所以str(df['latitude'])拿到的是整列纬度的字符串(类似0 38.0525\n1 40.7128\nName: latitude, dtype: object),不是单个有效坐标,传给reverse自然触发格式错误。
修正遍历方式
放弃for row in df的写法,改用df.apply()处理每一行(更符合Pandas操作风格),或使用iterrows()时正确提取单行数据(但apply效率更高)。
第二个错误:GeocoderTimedOut
Nominatim有严格的请求频率限制(非商业用途要求至少1秒间隔),批量请求不加延迟会被服务器拒绝,导致超时。另外,每次循环初始化Nominatim实例完全没必要,应该只初始化一次。
完整修正代码
import pandas as pd from geopy.geocoders import Nominatim from geopy.exc import GeocoderTimedOut, GeocoderUnavailable import time # 只初始化一次geolocator,避免重复创建连接 geolocator = Nominatim(user_agent='geoapiExercises') def get_state(row): # 提前处理空值或无效坐标 if pd.isna(row['latitude']) or pd.isna(row['longitude']): return '' try: # 直接传坐标元组,比拼接字符串更可靠 location = geolocator.reverse((row['latitude'], row['longitude']), timeout=10) if location and 'address' in location.raw: return location.raw['address'].get('state', '') return '' except (GeocoderTimedOut, GeocoderUnavailable): # 超时或服务不可用时,重试一次 time.sleep(2) try: location = geolocator.reverse((row['latitude'], row['longitude']), timeout=10) return location.raw['address'].get('state', '') if location else '' except (GeocoderTimedOut, GeocoderUnavailable): return '获取失败' finally: # 强制添加1秒延迟,遵守Nominatim的使用规则 time.sleep(1) # 读取数据并筛选美国数据 df = pd.read_csv('filepath.csv') us_df = df.loc[df['country_name'] == 'United States of America'].copy() # 应用函数生成state列 us_df['state'] = us_df.apply(get_state, axis=1) # 保存结果(可选) us_df.to_csv('us_data_with_state.csv', index=False)
关键修正点
- 单次初始化geolocator:避免重复创建客户端,提升请求效率。
- 用
apply处理每行:符合Pandas向量化操作逻辑,比iterrows更高效。 - 坐标传元组:
reverse支持直接传入(lat, lon)元组,避免字符串拼接出错。 - 异常捕获:处理超时、服务不可用的情况,防止程序中断。
- 强制延迟:每次请求后休眠1秒,严格遵守Nominatim的使用限制,避免被封禁。
- 空值预处理:提前过滤无效坐标,减少不必要的请求。
额外建议
如果数据量较大(10000条),可以考虑:
- 用
geopy.extra.rate_limiter.RateLimiter替代手动time.sleep,更灵活控制请求频率。 - 对已获取的结果做缓存,避免重复请求相同坐标。
内容的提问来源于stack exchange,提问作者Exquisite_Poupon
相关产品推荐
相关产品推荐

