用元组或 geopy.location.Location 格式的外部数据覆盖 (geo)pandas (geo)dataframe 中的单个有条件选择的单元格

Overwrite a single conditionally selected cell in a (geo)pandas (geo)dataframe with external data in tuple or geopy.location.Location format

我从一个 pandas 历史地点数据框开始。我将一列地名传递给 geopy 进行地理编码。我提取坐标,并将它们变成点。我还将地理编码器返回的 geopy.location.Location 保存在一个列中以供进一步使用。如果我在整个 (geo)dataframe 上 运行 这一切似乎都工作正常。

当我想覆盖一些条目时,问题就出现了。例如,我想覆盖地理编码器尝试但未能正确定位 'Fargo N Dak'(历史缩写)的任何地方。我可以在一个现代化的地名上重新运行 地理编码器并提取数据,但我不知道如何将其插入原始 gdf。

import numpy as np
import pandas as pd
import geopandas as gpd

from geopy.extra.rate_limiter import RateLimiter
from geopy.geocoders import Nominatim

#set up Nominatim geocoder with geopy package with a user_agent (required) and a rate limiter
Ngeocoder0 = Nominatim(user_agent="aGeocoder")
Ngeocoder = RateLimiter(Ngeocoder0.geocode, min_delay_seconds=1)

#make some toy data
lst = ['Minneapolis MN', 'Fargo ND', 'Fargo N Dak'] 
df = pd.DataFrame(lst,columns =['rawPOB'])

df['_TEMP'] = df['rawPOB'].apply(lambda x: Ngeocoder(x, language='en',addressdetails=True))

df['rawGCcoords']=df['_TEMP'].apply(lambda x: (x.point[1], x.point[0]) if x else None)
df['rawGClong']=df['_TEMP'].apply(lambda x: (x.point[1]) if x else None)
df['rawGClat']=df['_TEMP'].apply(lambda x: (x.point[0]) if x else None)

gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['rawGClong'], df['rawGClat']))


#so far so good, except Fargo N Dak is not recognized as Fargo North Dakota
#code just this place...
manualentry= Ngeocoder('Fargo North Dakota', language='en',addressdetails=True)
manualcoords=(manualentry.point[1], manualentry.point[0])

#... but here it all goes wrong when try to insert
gdf.loc[gdf.rawPOB == 'Fargo N Dak', '_TEMP'] = manualentry
gdf.loc[gdf.rawPOB == 'Fargo N Dak', 'rawGCcoords'] = manualcoords

#trying .at instead, and checking data type as in 
gdf.dtypes
gdf.at[gdf.rawPOB == 'Fargo N Dak', 'rawGCcoords'] = manualcoords

# :(

我错过了什么?

谢谢。

P.S。在此示例中,我当然可以在尝试对其进行地理编码之前清理数据,但我正在尝试构建一个工作流,在该工作流中我可以使用映射的、第一个地理编码结果来寻找不太明显的错误。

我猜这是由于您索引 GeoDataFrame 的方式所致。 当你在做

gdf.loc[gdf.rawPOB == 'Fargo N Dak', '_TEMP'] 你得到 pandas.Series in return (because you are using the boolean indexinggdf.rawPOB == '..')。所以你不能做你正在尝试的任务(并且应该得到像 ValueError: Must have equal len keys and value when setting with an iterable 这样的错误,这对 that 没有帮助) .

我建议您使用 rawPOB 列重新索引 GeoDataFrame,然后您将能够轻松地 set/get 使用DataFrame.at 方法如下:

gdf.set_index('rawPOB', inplace=True)

gdf.at['Fargo N Dak', '_TEMP'] = manualentry
gdf.at['Fargo N Dak', 'rawGCcoords'] = manualcoords

完成后,如果需要,您可以像以前一样重置索引:

gdf.reset_index(inplace=True)

我接受了 mgc 的回答,因为它符合我的要求。谢谢!

然而,这是一位同事想出的替代方案,它可以满足我的要求,因为它可以处理多个相同 rawPOB 的实例,就像当我们像这样设置数据:

`lst = ['Minneapolis MN', 'Fargo ND', 'Fargo N Dak', 'Fargo N Dak']

#and continue with...
df = pd.DataFrame(lst,columns =['rawPOB'])
df['_TEMP'] = df['rawPOB'].apply(lambda x: Ngeocoder(x, language='en',addressdetails=True))

df['rawGCcoords']=df['_TEMP'].apply(lambda x: (x.point[1], x.point[0]) if x else None)
df['rawGClong']=df['_TEMP'].apply(lambda x: (x.point[1]) if x else None)
df['rawGClat']=df['_TEMP'].apply(lambda x: (x.point[0]) if x else None)

gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df['rawGClong'], 
df['rawGClat']))
manualentry= Ngeocoder('Fargo North Dakota', language='en',addressdetails=True)
manualcoords=(manualentry.point[1], manualentry.point[0])

#NEW PART:
gdf['unique_id'] = pd.RangeIndex(stop=gdf.shape[0])
df_NOK = gdf.loc[gdf['rawPOB'] == 'Fargo N Dak' ]
for index, row in df_NOK.iterrows():
    gdf.at[index, 'rawGCcoords'] = manualcoords
    gdf.at[index, '_TEMP'] = manualentry`