Перезаписать одну условно выбранную ячейку в (geo) pandas (geo) dataframe внешними данными в формате tuple или geopy.location.Location - PullRequest
1 голос
/ 08 июля 2020

Я начинаю с pandas фрейма данных исторических мест. Я передаю столбец географических названий для геокодирования. Я извлекаю координаты и превращаю их в точки. Я также сохраняю возвращенный геокодером geopy.location.Location в столбце для дальнейшего использования. Кажется, все это работает нормально, если я запускаю его для всего (географического) фрейма данных.

Проблема возникает, когда я хочу перезаписать несколько записей. Например, я хочу перезаписать везде, где геокодер пытался и не смог правильно определить «Far go 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 https://stackoverflow.com/questions/27949671/add-a-tuple-to-a-specific-cell-of-a-pandas-dataframe
gdf.dtypes
gdf.at[gdf.rawPOB == 'Fargo N Dak', 'rawGCcoords'] = manualcoords

# :(

Что мне не хватает?

Спасибо.

PS В этом примере я, конечно, мог бы очистить данные, прежде чем пытаться их геокодировать, но я пытаюсь создать рабочий процесс, в котором я мог бы сначала использовать сопоставленные результаты геокодирования для поиска менее очевидных ошибок.

Ответы [ 2 ]

1 голос
/ 07 августа 2020

Я принял ответ mg c, поскольку он делает то, что я спросил . Спасибо!

Однако вот альтернатива, которую придумал коллега, которая делает то, что я хочу , потому что она может обрабатывать более одного экземпляра одного и того же 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`
1 голос
/ 08 июля 2020

Думаю, это связано с тем, как вы индексируете свой GeoDataFrame. Когда вы выполняете

gdf.loc[gdf.rawPOB == 'Fargo N Dak', '_TEMP'], вы получаете взамен pandas .Series (потому что вы используете логическое индексирование с gdf.rawPOB == '..'). Таким образом, вы не можете выполнить задание, которое пытаетесь выполнить (и вы должны получить сообщение об ошибке типа ValueError: Must have equal len keys and value when setting with an iterable, которое не , что полезно).

То, что я предлагаю заключается в том, что вы переиндексируете свой GeoDataFrame с помощью столбца rawPOB, тогда вы сможете легко установить / получить значение для указанной пары c (индекс, имя столбца), используя 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...