2017-10-04 111 views
2

我有存儲在大熊貓數據幀(df)與填充劑的斑點作爲NaN用於stop_id, stoplat, stoplon緯度和經度,並且在另一個數據幀areadf,其中包含多個拉特/經度和任意ID;這是要填充到df的信息。通過兩個大熊貓加快嵌套for循環DataFrames

我試圖連接兩個,以便df中的停止列包含有關最靠近該經緯度點的停靠點的信息,如果在該點的半徑R內沒有停止,則將其保留爲NaN

現在我的代碼如下,但它需要很長的時間(對於我目前正在運行的內容,需要40分鐘以上,在將區域更改爲df並使用itertuples之前;不確定差別有多大這將使?),因爲有成千上萬的經緯度點,並停止每一組數據,這是一個問題,因爲我需要在多個文件上運行此。我在尋找建議讓它運行得更快。我已經做了一些小小的改進(例如移動到一個數據框,使用itertuples而不是iterrows,在循環外定義lats和lons,以避免在每個循環中從df檢索它),但我沒有想法加快速度。 getDistance使用定義的Haversine公式來獲得停車標誌與給定經緯度之間的距離。

import pandas as pd 
from math import cos, asin, sqrt 

R=5 
lats = df['lat'] 
lons = df['lon'] 
for stop in areadf.itertuples(): 
    for index in df.index: 
     if getDistance(lats[index],lons[index], 
         stop[1],stop[2]) < R: 
      df.at[index,'stop_id'] = stop[0] # id 
      df.at[index,'stoplat'] = stop[1] # lat 
      df.at[index,'stoplon'] = stop[2] # lon 

def getDistance(lat1,lon1,lat2,lon2): 
    p = 0.017453292519943295  #Pi/180 
    a = (0.5 - cos((lat2 - lat1) * p)/2 + cos(lat1 * p) * 
     cos(lat2 * p) * (1 - cos((lon2 - lon1) * p))/2) 
    return 12742 * asin(sqrt(a)) * 100 

的樣本數據:

df 
lat  lon   stop_id stoplat stoplon 
43.657676 -79.380146 NaN  NaN  NaN 
43.694324 -79.334555 NaN  NaN  NaN 

areadf 
stop_id stoplat stoplon 
0   43.657675 -79.380145 
1   45.435143 -90.543253 

期望:

df 
lat  lon   stop_id stoplat stoplon 
43.657676 -79.380146 0   43.657675 -79.380145 
43.694324 -79.334555 NaN  NaN  NaN 
+0

你可以使用,而不是用Cython pypy,pypy編譯到c加快在蟒蛇循環 –

+3

1.不要遍歷這樣的dataframes,採取大熊貓的優勢2.使用歐幾里得距離作爲第一關,並拉出幾個最接近的點,因爲它比Haversine便宜3.將數據分成經緯網格,其中網格x及其周圍8個單元格中的任何內容都不在網格y中的任何東西的R內,並在子集停靠點上運行。 – jeremycg

+0

@jeremycg爲了更好地利用熊貓,你有沒有建議我研究的功能?謝謝您的回覆! – amper

回答

1

的一種方法是使用numpy的半正矢函數從here,只是略作修改,這樣就可以解釋半徑你要。

剛剛通過您的df與給定的半徑

def haversine_np(lon1, lat1, lon2, lat2,R): 
    """ 
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees) 
    All args must be of equal length.  
    """ 
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2]) 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2 
    c = 2 * np.arcsin(np.sqrt(a)) 
    km = 6367 * c 
    if km.min() <= R: 
     return km.argmin() 
    else: 
     return -1 

df['dex'] = df[['lat','lon']].apply(lambda row: haversine_np(row[1],row[0],areadf.stoplon.values,areadf.stoplat.values,1),axis=1) 

內申請,並找到最接近的值。然後合併這兩個dataframes迭代。

df.merge(areadf,how='left',left_on='dex',right_index=True).drop('dex',axis=1) 

     lat  lon stop_id stoplat stoplon 
0 43.657676 -79.380146  0.0 43.657675 -79.380145 
1 43.694324 -79.334555  NaN  NaN  NaN 

注意:如果您選擇按照這個方法,你必須確保兩個dataframes指標復位,或者他們是按順序從0責令DF的總LEN。所以一定要在運行這個之前重置索引。

df.reset_index(drop=True,inplace=True) 
areadf.reset_index(drop=True,inplace=True) 
+1

這對加速算法非常有用!從幾小時到幾秒,還比我使用上面提到的pycon優化實現的方法快了幾秒。非常感謝你! – amper