17

私は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

うまくいけばLambda関数を使用して、このようなものが欲しいです:

     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

助けていただければ幸いです。座標を取得したら、それらをマッピングしたいと思います。座標をマッピングするための推奨リソースも大歓迎です。ありがとう

4

2 に答える 2

18

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または、 2 回呼び出してワンライナーで実行します。

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それらから dict を作成してから、ルックアップを実行して座標を追加するように呼び出しますmap。これは、行単位でジオコーディングするよりも効率的です。

于 2015-07-14T18:34:51.067 に答える
4

@EdChumの回答に賛成票を投じて受け入れてください。これに追加したかっただけです。彼の方法は完璧に機能しますが、個人的な経験から、いくつかのことを共有したいと思います。

ジオコーディングを扱う場合、繰り返される都市/州の組み合わせが複数ある場合は、1 つだけを送信してジオコーディングし、残りを以下の他の行に複製する方がはるかに高速です。

これは、次の 2 つの方法で大規模なデータを処理できる場合に非常に役立ちます。

  1. 行が完全に重複しているように見えるため、データのみに基づいて、必要に応じて余分な行を削除し、それらの 1 つにジオコーディングを実行します。これは、drop_duplicate
  2. すべての行、group_by都市/州の組み合わせを保持する場合はhead(1)、 を呼び出して最初の行にジオコーディングを適用し、残りの行に複製します。

理由は、Nominatim を呼び出すたびに、同じ都市/州を連続してキューに入れていたとしても、わずかな遅延の問題があるためです。この小さな遅延は、データが大きくなるとさらに悪化し、応答が大幅に遅れてタイムアウトになる可能性があります。

繰り返しますが、これはすべて個人的に対処することからです。現時点で役に立たない場合は、将来の使用に備えて覚えておいてください。

于 2015-07-14T19:17:37.940 に答える