【问题标题】:How to calculate pairwise Euclidean distance between a collection of vectors如何计算向量集合之间的成对欧几里得距离
【发布时间】:2021-12-10 13:20:05
【问题描述】:

我有一个这样的熊猫数据框。其中索引是 pd.DatetimeIndex,列是时间序列。

x_1 x_2 x_3
2020-08-17 133.23 2457.45 -4676
2020-08-18 -982 -6354.56 -245.657
2020-08-19 5678.642 245.2786 2461.785
2020-08-20 -2394 154.34 -735.653
2020-08-20 236 -8876 -698.245

我需要计算所有列之间的欧几里得距离。即 (x_1 - x_2)、(x_1 - x_3)、(x_2 - x_3),并返回如下所示的方形数据框: (请注意,此表中的值只是一个示例,并非欧几里得距离的实际结果)

x_1 x_2 x_3
x_1 0 123 456
x_2 123 0 789
x_3 456 789 0

我尝试了this 资源,但我不知道如何传递我的 df 的列。如果理解正确,该示例将行作为序列传递以计算 ED。

【问题讨论】:

  • 你有一个 DatetimeIndex 并且列是时间序列的事实似乎无关紧要。你基本上有 3 个点,在 n 维空间(其中 n 是行数),你想计算欧几里得距离,对吧?
  • 欧几里得距离。我知道我可以做类似 np.linalg.norm(x_1 - x_2) 的事情。但我想同时计算所有列。输出应该看起来像第二个数据帧,尽管这些数字只是为了说明应该如何填充 df。
  • @Riley 是的,我想要所有列的欧几里得距离而不是行。

标签: python pandas distance series


【解决方案1】:

实现此目的的明确方法是:

from itertools import combinations

import numpy as np

dist_df = pd.DataFrame(index=df.columns, columns=df.columns)

for col_a, col_b in combinations(df.columns, 2):
    dist = np.linalg.norm(df[col_a] - df[col_b])
    dist_df.loc[col_a, col_b] = dist
    dist_df.loc[col_b, col_a] = dist

print(dist_df)

输出

              x_1           x_2           x_3
x_1           NaN  12381.858429   6135.306973
x_2  12381.858429           NaN  12680.121047
x_3   6135.306973  12680.121047           NaN

如果你想要0 而不是NaN,请使用DataFrame.fillna

dist_df.fillna(0, inplace=True)

【讨论】:

  • 此代码有效,但有一个错误,我使用了 itertools 产品而不是组合。原因是组合只会产生不同的列对。 ED 公式还计算 x_1 与 x_1 之类的情况。 stackoverflow.com/questions/23833780/…
  • @rbrt 不确定我看到了这个错误。此代码沿对角线生成 NaN,然后​​将它们更改为 0(这是预期距离)
  • 是的,但是通过使用 itertools 组合,它永远不会计算 x_1 与 x_1。我想这就是它返回 NaN 的原因。事实上,我使用相同的逻辑来计算同一数据集中的余弦相似度,它期望对角线为 1,它返回 NaN。这就是我注意到某些问题的原因,并发现将“组合”替换为“产品”解决了这个问题。
【解决方案2】:

以下代码适用于任意数量的列。

设置

df = pd.DataFrame(
    {
        "x1":[133.23, -982, 5678.642, -2394, 236],
        "x2":[2457.45, -6354.56, 245.2786, 154.34, -8876],
        "x3":[-4676, -245.657, 2461.785, -735.653, 698.245],
    }
)

解决方案

import numpy as np

aux = np.broadcast_to(df.values,  (df.shape[1], *df.shape))
result = np.sqrt(np.square(aux - aux.transpose()).sum(axis=1))

resultnumpy.array

如果您愿意,可以将其包装在数据框中

pd.DataFrame(result, columns=df.columns, index=df.columns)

              x1            x2            x3
x1      0.000000  12381.858429   6081.352512
x2  12381.858429      0.000000  13622.626775
x3   6081.352512  13622.626775      0.000000

为什么这种方法有效超出了我的意愿,并且需要强大的数学背景。您需要决定什么对您更重要:速度,或可读性/可理解性。

【讨论】:

  • “为什么这种方法有效超出了我的研究范围,并且需要强大的数学背景” 嗯?它几乎从字面上包含欧几里得距离公式。我会从答案中删除这个“绒毛”,特别是考虑到 OP 已经知道np.linalg.norm
  • 它涉及广播矩阵并使用 3 维矩阵计算向量之间的欧几里得距离。这不是微不足道的。
  • 此代码有效!但是,我决定不使用它,因为它超出了我的技能范围(尽管我阅读了有关广播的内容)并且我希望能够理解和解释代码。
  • 您还可以查看 scipy 距离指标docs.scipy.org/doc/scipy/reference/generated/…
猜你喜欢
  • 2014-06-14
  • 2021-02-11
  • 1970-01-01
  • 2014-08-15
  • 1970-01-01
  • 2020-09-25
  • 2016-05-11
  • 2019-06-06
  • 1970-01-01
相关资源
最近更新 更多