【问题标题】: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 testeinsum 与其他几个同行进行比较。

【讨论】:

    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2020-05-13
      • 2015-06-10
      • 2021-10-10
      • 2017-02-05
      • 2021-12-30
      • 2018-05-08
      • 1970-01-01
      • 2015-06-02
      • 1970-01-01
      相关资源
      最近更新 更多