новый столбец с координатами с использованием geopy pandas

у меня есть df:

import pandas as pd
import numpy as np
import datetime as DT
import hmac
from geopy.geocoders import Nominatim
from geopy.distance import vincenty

df


     city_name  state_name  county_name
0    WASHINGTON  DC  DIST OF COLUMBIA
1    WASHINGTON  DC  DIST OF COLUMBIA
2    WASHINGTON  DC  DIST OF COLUMBIA
3    WASHINGTON  DC  DIST OF COLUMBIA
4    WASHINGTON  DC  DIST OF COLUMBIA
5    WASHINGTON  DC  DIST OF COLUMBIA
6    WASHINGTON  DC  DIST OF COLUMBIA
7    WASHINGTON  DC  DIST OF COLUMBIA
8    WASHINGTON  DC  DIST OF COLUMBIA
9    WASHINGTON  DC  DIST OF COLUMBIA

Я хочу получить координаты широты и долготы для любого из столбцов в фрейме данных ниже. Документация (http://geopy.readthedocs.org/en/latest/#data) довольно просто при работе с документацией для отдельных местоположений.

>>> from geopy.geocoders import Nominatim
>>> geolocator = Nominatim()
>>> location = geolocator.geocode("175 5th Avenue NYC")
>>> print(location.address)
Flatiron Building, 175, 5th Avenue, Flatiron, New York, NYC, New York,     ...
>>> print((location.latitude, location.longitude))
(40.7410861, -73.9896297241625)
>>> print(location.raw)
{'place_id': '9167009604', 'type': 'attraction', ...}

однако я хочу применить функцию к каждой строке в df и сделать новый столбец. Я пробовал следующее

df['city_coord'] = geolocator.geocode(lambda row: 'state_name' (row))

но я думаю, мне чего-то не хватает в моем коде, потому что я получаю следующее:

    city_name   state_name  county_name coordinates
0    WASHINGTON  DC  DIST OF COLUMBIA    None
1    WASHINGTON  DC  DIST OF COLUMBIA    None
2    WASHINGTON  DC  DIST OF COLUMBIA    None
3    WASHINGTON  DC  DIST OF COLUMBIA    None
4    WASHINGTON  DC  DIST OF COLUMBIA    None
5    WASHINGTON  DC  DIST OF COLUMBIA    None
6    WASHINGTON  DC  DIST OF COLUMBIA    None
7    WASHINGTON  DC  DIST OF COLUMBIA    None
8    WASHINGTON  DC  DIST OF COLUMBIA    None
9    WASHINGTON  DC  DIST OF COLUMBIA    None

Я хотел бы что-то вроде этого, надеюсь, используя лямбда-функции:

     city_name  state_name  county_name  city_coord
0    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
1    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
2    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
3    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
4    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
5    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
6    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
7    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
8    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456 
9    WASHINGTON  DC  DIST OF COLUMBIA    38.8949549, -77.0366456
10   GLYNCO      GA  GLYNN               31.2224512, -81.5101023

Я ценю любую помощь. После того, как я получу координаты, я хотел бы нанести их на карту. Любые рекомендуемые ресурсы для отображения координат также очень ценятся. спасибо

2 ответов


можно назвать apply и передайте функцию, которую вы хотите выполнить в каждой строке, следующим образом:

In [9]:

geolocator = Nominatim()
df['city_coord'] = df['state_name'].apply(geolocator.geocode)
df
Out[9]:
    city_name state_name       county_name  \
0  WASHINGTON         DC  DIST OF COLUMBIA   
1  WASHINGTON         DC  DIST OF COLUMBIA   

                                          city_coord  
0  (District of Columbia, United States of Americ...  
1  (District of Columbia, United States of Americ...  

затем вы можете получить доступ к атрибутам широты и долготы:

In [16]:

df['city_coord'] = df['city_coord'].apply(lambda x: (x.latitude, x.longitude))
df
Out[16]:
    city_name state_name       county_name                       city_coord
0  WASHINGTON         DC  DIST OF COLUMBIA  (38.8937154, -76.9877934586326)
1  WASHINGTON         DC  DIST OF COLUMBIA  (38.8937154, -76.9877934586326)

или сделать это в одном лайнере, позвонив apply дважды:

In [17]:
df['city_coord'] = df['state_name'].apply(geolocator.geocode).apply(lambda x: (x.latitude, x.longitude))
df

Out[17]:
    city_name state_name       county_name                       city_coord
0  WASHINGTON         DC  DIST OF COLUMBIA  (38.8937154, -76.9877934586326)
1  WASHINGTON         DC  DIST OF COLUMBIA  (38.8937154, -76.9877934586326)

также ваша попытка geolocator.geocode(lambda row: 'state_name' (row)) ничего не сделал, поэтому у вас есть столбец полный None значения

редактировать

@leb делает интересный момент здесь, если у вас есть много повторяющихся значений, тогда будет более эффективно геокодировать для каждого уникального значения, а затем добавить это:

In [38]:
states = df['state_name'].unique()
d = dict(zip(states, pd.Series(states).apply(geolocator.geocode).apply(lambda x: (x.latitude, x.longitude))))
d

Out[38]:
{'DC': (38.8937154, -76.9877934586326)}

In [40]:    
df['city_coord'] = df['state_name'].map(d)
df

Out[40]:
    city_name state_name       county_name                       city_coord
0  WASHINGTON         DC  DIST OF COLUMBIA  (38.8937154, -76.9877934586326)
1  WASHINGTON         DC  DIST OF COLUMBIA  (38.8937154, -76.9877934586326)

таким образом, выше получает все уникальные значения, используя unique, строит дикт из них, а затем вызывает map выполнить поиск и добавить координаты, это будет более эффективно, чем пытаться геокодирования построчный


Upvote и принять ответ @EdChum, я просто хотел добавить к этому. Его методы работают отлично, но из личного опыта я хотел бы поделиться несколькими вещами:

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

Это очень полезно для больших данных можно сделать через два пути:

  1. на основе ваших данных только потому, что строки кажутся точными дубликатами, и только если вы хотите, отбросьте дополнительные и выполните геокодирование на один из них. Это можно сделать с помощью drop_duplicate
  2. если вы хотите сохранить все ваши строки group_by комбинация город / штат, примените геокодирование к нему первым, вызвав head(1), затем дублируйте остальные строки.

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

опять же, это все из personanly справиться с ним. Просто имейте в виду для будущего использования, если это не принесет вам пользу сейчас.