如何计算向量集合之间的成对欧氏距离
How to calculate pairwise Euclidean distance between a collection of vectors
我有一个这样的 pandas 数据框。其中索引为 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) 和 return像这样的方形数据框:
(请注意table中的值只是一个例子,并不是欧式距离的实际结果)
x_1
x_2
x_3
x_1
0
123
456
x_2
123
0
789
x_3
456
789
0
我尝试了 this 资源,但我不知道如何传递我的 df 的列。如果理解正确,该示例将行作为系列传递以计算 ED。
实现此目的的明确方法是:
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)
以下代码适用于任意数量的列。
设置
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))
result
是一个 numpy.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
为什么这种方法有效超出了我愿意深入的范围并且需要强大的数学背景。您需要决定什么对您更重要:速度,还是 readability/understandability.
我有一个这样的 pandas 数据框。其中索引为 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) 和 return像这样的方形数据框: (请注意table中的值只是一个例子,并不是欧式距离的实际结果)
x_1 | x_2 | x_3 | |
---|---|---|---|
x_1 | 0 | 123 | 456 |
x_2 | 123 | 0 | 789 |
x_3 | 456 | 789 | 0 |
我尝试了 this 资源,但我不知道如何传递我的 df 的列。如果理解正确,该示例将行作为系列传递以计算 ED。
实现此目的的明确方法是:
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)
以下代码适用于任意数量的列。
设置
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))
result
是一个 numpy.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
为什么这种方法有效超出了我愿意深入的范围并且需要强大的数学背景。您需要决定什么对您更重要:速度,还是 readability/understandability.