在 Pandas 个数据帧之间匹配 ID 并应用函数

Matching IDs Between Pandas DataFrames and Applying Function

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

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 和 df_A 中的 x,y 坐标之间的欧几里得距离。期望的结果是:

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 为条件?

如果 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

由于索引和列已经对齐,简单地计算一下就可以了。

使用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

为了提高性能,您可能希望使用 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

这里是 比较 einsum 和少数其他同行。