在非常大的pandas数据框上进行pyproj.Geod计算
背景:
我有一个包含大约20万行数据的pandas数据框。
<class 'pandas.core.frame.DataFrame'>
Int64Index: 212812 entries, 0 to 212811
Data columns (total 10 columns):
date 212812 non-null values
animal_id 212812 non-null values
lons 212812 non-null values
lats 212812 non-null values
depth 212812 non-null values
prey1 212812 non-null values
prey2 212812 non-null values
prey3 212812 non-null values
dist 212812 non-null values
sog 212812 non-null values
dtypes: float64(9), int64(1), object(1)
每个日期都有1000个人的经纬度位置。
我想计算每个人每天的距离变化,我之前成功地对100个人做到了这一点,使用的是pyproj.Geod.inv这个工具,但随着人数的增加,计算速度变得非常慢。
问题:
有没有什么高效的方法可以使用像pyproj.Geod.inv
这样的外部类方法来对pandas数据框进行计算?
示例程序:
ids = np.unique(data['animal_id'])
for animal in ids:
id_idx = data['animal_id']==animal
dates = data['date'][id_idx]
for i in range(len(dates)-1):
idx1 = (data['animal_id']==id) & (data['date']==dates[i])
idx2 = (data['animal_id']==id) & (data['date']==dates[i+1])
lon1 = data['lons'][idx1]
lat1 = data['lats'][idx1]
lon2 = data['lons'][idx2]
lat2 = data['lats'][idx2]
fwd_az, bck_az, dist = g.inv(lon1,lat1,lon2,lat2)
data['dist'][idx2] = dist
data['sog'][idx2] = dist/24. #dist/time(hours)
1 个回答
0
我想出了一个解决方案,但我很希望能听到其他做法的建议,或者有没有更高效的方式来实现我的方案。
首先,我使用了 pandas
的 shift
方法,添加了偏移的经纬度列(这个SO问题给了我灵感),这样我就可以在一行数据上进行计算。
接着,我使用了 pandas
的 apply
方法(这里有建议),来实现 pyproj.Geod.inv
的计算,针对每个人口中的个体,循环处理 pandas
的 DataFrame
的切片。
def calc_distspd(df):
'''Broadcast pyproj distance calculation over pandas dataframe'''
import pyproj
import numpy as np
def calcdist(x):
'''Pandas broadcast function for pyproj distance calculations'''
return g.inv(x['lons+1'], x['lats+1'], x['lons'], x['lats'])[2]
# Define Earth ellipsoid for dist calculations
g = pyproj.Geod(ellps='WGS84')
# Create array of zeros to initialize new columns
fill_data = np.zeros(df['date'].shape)
# Create new columns for calculated vales
df['dist'] = fill_data
df['sog'] = fill_data
df['lons+1'] = fill_data
df['lats+1'] = fill_data
# Get list of unique animal_ids
animal_ids = np.unique(df.animal_id.values)
# Peform function broadcast for each individual
for animal_id in animal_ids:
idx = df['animal_id']==animal_id
# Add shifted position columns for dist calculations
df['lons+1'] = df['lons'].shift(1) # lon+1 = origin position
df['lats+1'] = df['lats'].shift(1) # lat+1 = origin position
# Copy 1st position over shifted column nans to prevent error
idx2 = (idx) & (np.isnan(df[lons+1]))
df['lons+1'][idx2] = df['lons'][idx2]
df['lats+1'][idx2] = df['lats'][idx2]
df['dist'][idx] = df[idx].apply(calcdist, axis=1)
df['sog'][idx] = df['dist']/24. # Calc hourly speed
# Remove shifted position columns from df
del df['lons+1']
del df['lats+1']
return df