【问题标题】:Matching IDs Between Pandas DataFrames and Applying Function在 Pandas DataFrames 和应用函数之间匹配 ID
【发布时间】:2017-05-10 02:21:12
【问题描述】:
我有两个如下所示的数据框:
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 为条件?
【问题讨论】:
标签:
python
performance
pandas
numpy
apply
【解决方案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 与其他几个同行进行比较。
【解决方案2】:
如果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
由于索引和列已经对齐,只需进行数学运算即可。
【解决方案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