匹配Pandas DataFrames和应用函数之间的ID

时间:2016-12-24 22:40:03

标签: python performance pandas numpy apply

我有两个数据框如下所示:

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时使用它?

3 个答案:

答案 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与其他几个对手的比较。