使用lru_cache缓存地址经纬度解析结果时遇列长度不匹配错误
问题:地址解析经纬度时缓存报错
ValueError: Columns must be same length as key 问题场景
需要从DataFrame的地址列提取经纬度,同时用lru_cache缓存已解析的地址结果以避免重复调用地理编码接口,但运行代码时触发上述错误。
原始DataFrame
address customer 0 Surlej, 7513, Silvaplana, Schweiz 1 1 Vodnikova cesta 35, 1000 Ljubljana, Slowenien 2 2 Surlej, 7513, Silvaplana, Schweiz 1
原始代码
from functools import lru_cache from geopy.geocoders import Nominatim geolocator = Nominatim(user_agent='testing_stackoverflow') import pandas as pd d = { "address": ['Surlej, 7513, Silvaplana, Schweiz', 'Vodnikova cesta 35, 1000 Ljubljana, Slowenien', 'Surlej, 7513, Silvaplana, Schweiz',], "customer": [1, 2, 1], } df = pd.DataFrame(data=d) print(df) @lru_cache(maxsize=None) def function_that_returns_lat_lon_from_address(address): location = geolocator.geocode(address, timeout=10) print(location) try: if (location == None): return(None, None) else: return (location.latitude, location.longitude) except GeocoderTimedOut as e: print("Timeout ", e) return(None, None) df[['lat', 'lon']] = df['address'].apply(function_that_returns_lat_lon_from_address)
期望输出
address customer lat lon 0 Surlej, 7513, Silvaplana, Schweiz 1 46.459902 9.803370 1 Vodnikova cesta 35, 1000 Ljubljana, Slowenien 2 46.065523 14.490775 2 Surlej, 7513, Silvaplana, Schweiz 1 46.459902 9.803370
报错信息
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-8-4873cdd27090> in <module>() 24 return(None, None) 25 ---> 26 df[['lat', 'lon']] = df['address'].apply(function_that_returns_lat_lon_from_address) 2 frames /usr/local/lib/python3.7/dist-packages/pandas/core/frame.py in _iset_not_inplace(self, key, value) 3673 if self.columns.is_unique: 3674 if np.shape(value)[-1] != len(key): -> 3675 raise ValueError("Columns must be same length as key") 3676 3677 for i, col in enumerate(key): ValueError: Columns must be same length as key
错误原因
df['address'].apply()返回的是元素为元组的Series,直接赋值给多列时,pandas无法自动将元组拆分为对应列的数值。此外,原代码未导入GeocoderTimedOut异常类,会导致额外报错。
解决方法
- 将
apply的结果转换为pd.Series,让pandas自动拆分元组为多列 - 导入缺失的
GeocoderTimedOut异常类 - 保留
lru_cache的缓存逻辑,确保重复地址只查询一次
修正后的完整代码
from functools import lru_cache from geopy.geocoders import Nominatim from geopy.exc import GeocoderTimedOut # 导入缺失的异常类 geolocator = Nominatim(user_agent='testing_stackoverflow') import pandas as pd d = { "address": ['Surlej, 7513, Silvaplana, Schweiz', 'Vodnikova cesta 35, 1000 Ljubljana, Slowenien', 'Surlej, 7513, Silvaplana, Schweiz',], "customer": [1, 2, 1], } df = pd.DataFrame(data=d) @lru_cache(maxsize=None) def get_lat_lon(address): location = geolocator.geocode(address, timeout=10) try: if location is None: return (None, None) return (location.latitude, location.longitude) except GeocoderTimedOut: print(f"地址 {address} 解析超时") return (None, None) # 将apply结果转为Series,自动拆分到两列 df[['lat', 'lon']] = df['address'].apply(get_lat_lon).apply(pd.Series) print(df)
运行结果
address customer lat lon 0 Surlej, 7513, Silvaplana, Schweiz 1 46.459902 9.803370 1 Vodnikova cesta 35, 1000 Ljubljana, Slowenien 2 46.065523 14.490775 2 Surlej, 7513, Silvaplana, Schweiz 1 46.459902 9.803370
内容的提问来源于stack exchange,提问作者Test
相关产品推荐
相关产品推荐

