Use*_*rR6 3 python euclidean-distance dataframe pandas
随着时间的推移,我有一组对象及其位置。我想获得每辆车与其最近邻居之间的距离,并计算每个时间点的平均值。示例数据框如下:
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
Run Code Online (Sandbox Code Playgroud)
对于每个时间点,我想知道每辆车最近的汽车邻居。例子:
df2
car nearest_neighbour euclidean_distance
time
0 1 3 1.41
0 2 3 1.00
0 3 1 1.41
1 1 3 10.05
1 3 1 10.05
2 4 5 53.04
2 5 4 53.04
Run Code Online (Sandbox Code Playgroud)
我知道我可以从How to apply euclidean distance function to a groupby object in pandas dataframe 计算汽车之间的成对距离?但是我如何获得每辆车的最近邻居?
之后,使用 groupby 获得每帧距离的平均值似乎很简单,但它的第二步真正让我失望。帮助表示赞赏!
这可能有点矫枉过正,但您可以使用scikit 中的最近邻居
一个例子:
import numpy as np
from sklearn.neighbors import NearestNeighbors
import pandas as pd
def nn(x):
nbrs = NearestNeighbors(n_neighbors=2, algorithm='auto', metric='euclidean').fit(x)
distances, indices = nbrs.kneighbors(x)
return distances, indices
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})
#This has the index of the nearest neighbor in the group, as well as the distance
nns = df.drop('car', 1).groupby('time').apply(lambda x: nn(x.as_matrix()))
groups = df.groupby('time')
nn_rows = []
for i, nn_set in enumerate(nns):
group = groups.get_group(i)
for j, tup in enumerate(zip(nn_set[0], nn_set[1])):
nn_rows.append({'time': i,
'car': group.iloc[j]['car'],
'nearest_neighbour': group.iloc[tup[1][1]]['car'],
'euclidean_distance': tup[0][1]})
nn_df = pd.DataFrame(nn_rows).set_index('time')
Run Code Online (Sandbox Code Playgroud)
结果:
car euclidean_distance nearest_neighbour
time
0 1 1.414214 3
0 2 1.000000 3
0 3 1.000000 2
1 1 10.049876 3
1 3 10.049876 1
2 4 53.037722 5
2 5 53.037722 4
Run Code Online (Sandbox Code Playgroud)
(请注意,在时间 0,汽车 3 的最近邻居是汽车 2。sqrt((217-216)**2 + 1)大约是1.4142135623730951while sqrt((218-217)**2 + 0) = 1)
使用cdistfromscipy.spatial.distance得到一个矩阵,表示每辆车到其他每辆车的距离。由于每辆车到自身的距离都是0,所以对角线元素都为0。
示例(对于time == 0):
X = df[df.time==0][['x','y']]
dist = cdist(X, X)
dist
array([[0. , 2.23606798, 1.41421356],
[2.23606798, 0. , 1. ],
[1.41421356, 1. , 0. ]])
Run Code Online (Sandbox Code Playgroud)
使用np.argsort获取对距离矩阵进行排序的索引。第一列只是行号,因为对角线元素为 0。
idx = np.argsort(dist)
idx
array([[0, 2, 1],
[1, 2, 0],
[2, 1, 0]], dtype=int64)
Run Code Online (Sandbox Code Playgroud)
然后,只需使用以下命令选择汽车和最近距离idx
dist[v[:,0], v[:,1]]
array([1.41421356, 1. , 1. ])
df[df.time==0].car.values[v[:,1]]
array([3, 3, 2], dtype=int64)
Run Code Online (Sandbox Code Playgroud)
将上述逻辑组合成一个返回所需数据帧的函数:
def closest(df):
X = df[['x', 'y']]
dist = cdist(X, X)
v = np.argsort(dist)
return df.assign(euclidean_distance=dist[v[:, 0], v[:, 1]],
nearest_neighbour=df.car.values[v[:, 1]])
Run Code Online (Sandbox Code Playgroud)
& 将其与 groupby 一起使用,最后删除索引,因为 groupby-apply 添加了额外的索引
df.groupby('time').apply(closest).reset_index(drop=True)
time x y car euclidean_distance nearest_neighbour
0 0 216 13 1 1.414214 3
1 0 218 12 2 1.000000 3
2 0 217 12 3 1.000000 2
3 1 280 110 1 10.049876 3
4 1 290 109 3 10.049876 1
5 2 130 3 4 53.037722 5
6 2 132 56 5 53.037722 4
Run Code Online (Sandbox Code Playgroud)
顺便说一句,你的样本输出在时间 0 时是错误的。我的答案和培根的答案都显示了正确的结果
| 归档时间: |
|
| 查看次数: |
2661 次 |
| 最近记录: |