我有两个数据框如下所示:
DF_A:
ID x y
a 0 0
c 3 2
b 2 5
DF_B:
ID x y
a 2 1
c 3 5
b 1 2
我想在db_B中添加一个列,该列是df_B中x,y坐标与df_A之间的欧几里德距离,用于每个标识符。期望的结果是:
ID x y dist
a 2 1 1.732
c 3 5 3
b 1 2 3.162
标识符不一定是相同的顺序。我知道如何通过循环遍历df_A行并在df_B中找到匹配的ID来做到这一点,但我希望避免使用for循环,因为这将用于具有数千万行的数据。是否有某种方法可以使用apply但是在匹配ID时使用它?
答案 0 :(得分:4)
如果ID
不是索引,那么就这样做。
df_B.set_index('ID', inplace=True)
df_A.set_index('ID', inplace=True)
df_B['dist'] = ((df_A - df_B) ** 2).sum(1) ** .5
由于索引和列已经对齐,因此只需进行数学运算即可。
答案 1 :(得分:3)
使用sklearn.metrics.pairwise.paired_distances方法的解决方案:
In [73]: A
Out[73]:
x y
ID
a 0 0
c 3 2
b 2 5
In [74]: B
Out[74]:
x y
ID
a 2 1
c 3 5
b 1 2
In [75]: from sklearn.metrics.pairwise import paired_distances
In [76]: B['dist'] = paired_distances(B, A)
In [77]: B
Out[77]:
x y dist
ID
a 2 1 2.236068
c 3 5 3.000000
b 1 2 3.162278
答案 2 :(得分:1)
为了提高性能,您可能希望使用NumPy数组,并且对于相应行之间的欧几里德距离计算,np.einsum
可以非常有效地进行。
结合行的固定以使它们对齐,这是一个实现 -
# Get sorted row indices for dataframe-A
sidx = df_A.index.argsort()
idx = sidx[df_A.index.searchsorted(df_B.index,sorter=sidx)]
# Sort A rows accordingly and get the elementwise differences against B
s = df_A.values[idx] - df_B.values
# Use einsum to square and sum each row and finally sqrt for distances
df_B['dist'] = np.sqrt(np.einsum('ij,ij->i',s,s))
示例输入,输出 -
In [121]: df_A
Out[121]:
0 1
a 0 0
c 3 2
b 2 5
In [122]: df_B
Out[122]:
0 1
c 3 5
a 2 1
b 1 2
In [124]: df_B # After code run
Out[124]:
0 1 dist
c 3 5 3.000000
a 2 1 2.236068
b 1 2 3.162278
这是runtime test
比较einsum
与其他几个对手的比较。