Как применить евклидову функцию расстояния к групповому объекту в кадре данных панд? - PullRequest
0 голосов
/ 27 июня 2018

У меня есть набор объектов и их положение с течением времени. Я хотел бы получить среднее расстояние между объектами для каждой временной точки. Пример кадра данных выглядит следующим образом:

time = [0, 0, 0, 1, 1, 2, 2]
x = [216, 218, 217, 280, 290, 130, 132]
y = [13, 12, 12, 110, 109, 3, 56]
car = [1, 2, 3, 1, 3, 4, 5]
df = pd.DataFrame({'time': time, 'x': x, 'y': y, 'car': car})
df

             x       y      car
     time
      0     216     13       1
      0     218     12       2
      0     217     12       3
      1     280     110      1
      1     290     109      3
      2     130     3        4
      2     132     56       5

Конечный результат, который я хотел бы получить:

df2

              average distance
              between cars       
     time
      0           1.55     
      1           10.05     
      2           53.04    

есть идеи, как поступить? Я пытался применить функцию scipy.spatial.distance к фрейму данных, но я не уверен, как применить его к df.groupby ('time'), а затем получить среднее значение всех этих расстояний. Любая помощь приветствуется!

Ответы [ 4 ]

0 голосов
/ 27 июня 2018

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

 import itertools
 import numpy as np

 def combinations(series):
        l = list()
        for item in itertools.combinations(series,2):
            l.append(((item[0] - item[1])**2))
        return l

df2 = df.groupby('time').agg(combinations)
df2['avg_distance'] = [np.mean(np.sqrt(pd.Series(df2.iloc[k,0]) + 
pd.Series(df2.iloc[k,1]))) for k in range(len(df2))]

df2.avg_distance.to_frame()

Тогда вывод:

    avg_distance
time    
0   1.550094
1   10.049876
2   53.037722
0 голосов
/ 27 июня 2018

построение этого из первых принципов:

Для каждой точки с индексом n необходимо вычислить расстояние со всеми точками с индексом> n.

если расстояние между двумя точками определяется по формуле:

np.sqrt((x0 - x1)**2 + (y0 - y1)**2)

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

distances = []
for i in range(len(df)-1):
    distances += np.sqrt( (df.x[i+1:] - df.x[i])**2 + (df.y[i+1:] - df.y[i])**2 ).tolist()

np.mean(distances)

выражая ту же логику, используя pd.concat и пару вспомогательных функций

def diff_sq(x, i):
    return (x.iloc[i+1:] - x.iloc[i])**2

def dist_df(x, y, i):
    d_sq = diff_sq(x, i) + diff_sq(y, i)
    return np.sqrt(d_sq)

def avg_dist(df):
    return pd.concat([dist_df(df.x, df.y, i) for i in range(len(df)-1)]).mean()

тогда можно использовать функцию avg_dist с groupby

df.groupby('time').apply(avg_dist)
# outputs:
time
0     1.550094
1    10.049876
2    53.037722
dtype: float64
0 голосов
/ 27 июня 2018

Вы можете передать массив точек на scipy.spatial.distaince.pdist, и он вычислит все попарные расстояния между Xi и Xj для i> j. Тогда возьми среднее.

import numpy as np
from scipy import spatial

df.groupby('time').apply(lambda x: spatial.distance.pdist(np.array(list(zip(x.x, x.y)))).mean())

Выходы:

time
0     1.550094
1    10.049876
2    53.037722
dtype: float64
0 голосов
/ 27 июня 2018

Для меня использование apply или for loop не сильно отличается

l1=[]
l2=[]

for y,x in df.groupby('time'):
    v=np.triu(spatial.distance.cdist(x[['x','y']].values, x[['x','y']].values),k=0)

    v = np.ma.masked_equal(v, 0)
    l2.append(np.mean(v))
    l1.append(y)


pd.DataFrame({'ave':l2},index=l1)

Out[250]: 
         ave
0   1.550094
1  10.049876
2  53.037722
...