因此,如果我理解正确,您正在尝试传输采样分布,即计算所有集群的权重为 1 的设置的距离。通常,您可以将 EMD 的计算视为最小成本流的实例,在您的情况下,这归结为线性分配问题:您的两个数组是二分图中的分区,两个顶点之间的权重是您选择的距离。假设您想使用欧几里得范数作为度量,则可以使用 获得边缘的权重,即地面距离,scipy.spatial.distance.cdist
实际上 SciPy 也为线性和分配问题提供了求解器scipy.optimize.linear_sum_assignment
(最近看到了 SciPy 1.4 中可用的巨大性能改进。如果您遇到性能问题,这可能会引起您的兴趣;对于 1000x1000 输入,1.3 实现有点慢)。
换句话说,你想做的归结为
from scipy.spatial.distance import cdist
from scipy.optimize import linear_sum_assignment
d = cdist(Y1, Y2)
assignment = linear_sum_assignment(d)
print(d[assignment].sum() / n)
也可以用作 ;scipy.sparse.csgraph.min_weight_bipartite_full_matching
的替代品linear_sum_assignment
。虽然用于稀疏输入(您的输入肯定不是),但它可能会在某些情况下提供性能改进。
验证此计算的结果是否与您从最小成本流求解器中获得的结果相匹配可能是有益的;NetworkX中提供了一个这样的求解器,我们可以在其中手动构建图形:
import networkx as nx
G = nx.DiGraph()
# Represent elements in Y1 by 0, ..., 999, and elements in
# Y2 by 1000, ..., 1999.
for i in range(n):
G.add_node(i, demand=-1)
G.add_node(n + i, demand=1)
for i in range(n):
for j in range(n):
G.add_edge(i, n + j, capacity=1, weight=d[i, j])
此时,我们可以验证上述方法是否符合最小成本流:
In [16]: d[assignment].sum() == nx.algorithms.min_cost_flow_cost(G)
Out[16]: True
同样,看到结果与scipy.stats.wasserstein_distance
一维输入一致是有益的:
from scipy.stats import wasserstein_distance
np.random.seed(0)
n = 100
Y1 = np.random.randn(n)
Y2 = np.random.randn(n) - 2
d = np.abs(Y1 - Y2.reshape((n, 1)))
assignment = linear_sum_assignment(d)
print(d[assignment].sum() / n) # 1.9777950447866477
print(wasserstein_distance(Y1, Y2)) # 1.977795044786648