我怎样才能更快地将我的 for 循环工作转移到 pandas 应用功能?

How can I transfer my working for loop over to pandas much quicker apply functionality?

我有一个包含经度和纬度列的数据框。我需要在 geoPy 包的帮助下根据 long 和 lat 值获取该位置的县名。

 longitude  latitude  housing_median_age  total_rooms  total_bedrooms  \
0    -114.31     34.19                15.0       5612.0          1283.0   
1    -114.47     34.40                19.0       7650.0          1901.0   
2    -114.56     33.69                17.0        720.0           174.0   
3    -114.57     33.64                14.0       1501.0           337.0   
4    -114.57     33.57                20.0       1454.0           326.0   

   population  households  median_income  median_house_value  
0      1015.0       472.0         1.4936             66900.0  
1      1129.0       463.0         1.8200             80100.0  
2       333.0       117.0         1.6509             85700.0  
3       515.0       226.0         3.1917             73400.0  
4       624.0       262.0         1.9250             65500.0

我使用 for 循环成功了:

geolocator = geopy.Nominatim(user_agent='1234')

for index, row in df.iloc[:10, :].iterrows():
    location = geolocator.reverse([row["latitude"], row["longitude"]])
    county = location.raw['address']['county']
    print(county)

数据集有 17,000 行,所以这应该是个问题吧?

所以我一直在想办法构建一个可以在 pandas.apply() 中使用的函数,以便更快地获得结果。

def get_zipcodes():
    location = geolocator.reverse([row["latitude"], row["longitude"]])
    county = location.raw['address']['county']
    print(county)

counties = get_zipcodes()

我被卡住了,不知道如何在这里使用应用(或任何其他聪明的方法)。非常感谢帮助。

您代码中的 pandas 计算不太可能成为使用 geopy 时的速度瓶颈(参见 this answer 另一个 geopy 问题)。

但是,如果可能有大量行具有重复的 latitude, longitude 坐标,您可以使用 functools 中的 @cache(或 @lru_cache(None))装饰器。

以下是如何在没有特殊缓存的情况下在数据帧上使用 apply()

df["county"] = df.apply(lambda row: geolocator.reverse([row["latitude"], row["longitude"]]).raw["address"]["county"], axis=1)

完整测试代码:

import geopy
geolocator = geopy.Nominatim(user_agent='1234')
import pandas as pd
df = pd.DataFrame({
'longitude':[-114.31,-114.47,-114.56,-114.57,-114.57], 
'latitude':[34.19,34.40,33.69,33.64,33.57], 
'housing_median_age':[15]*5, 
'total_rooms':[1000]*5, 
'total_bedrooms':[500]*5, 
'population':[800]*5})

print(df)

df["county"] = df.apply(lambda row: geolocator.reverse([row["latitude"], row["longitude"]]).raw["address"]["county"], axis=1)
print(df)

输入:

   longitude  latitude  housing_median_age  total_rooms  total_bedrooms  population
0    -114.31     34.19                  15         1000             500         800
1    -114.47     34.40                  15         1000             500         800
2    -114.56     33.69                  15         1000             500         800
3    -114.57     33.64                  15         1000             500         800
4    -114.57     33.57                  15         1000             500         800

输出:

   longitude  latitude  housing_median_age  total_rooms  total_bedrooms  population                 county
0    -114.31     34.19                  15         1000             500         800  San Bernardino County
1    -114.47     34.40                  15         1000             500         800  San Bernardino County
2    -114.56     33.69                  15         1000             500         800       Riverside County
3    -114.57     33.64                  15         1000             500         800       Riverside County
4    -114.57     33.57                  15         1000             500         800       Riverside County

以下是如何使用装饰器缓存相同 latitude, longitude 坐标的结果(即避免多次到达 geopy 服务器):

from functools import cache
@cache
def bar(lat, long):
    return geolocator.reverse([lat, long]).raw["address"]["county"]

def foo(row):
    return bar(row["latitude"], row["longitude"])
df["county"] = df.apply(foo, axis=1)