在Python中,有没有一种方法可以测量多维空间中两个分布之间的距离?

7

我希望能够在多维空间中测量两个分布之间的距离。

例如,我想进行如Wasserstein距离或能量距离等多维度的度量,而非仅限于一维比较。

我已经找到了1D情况下的相关软件包,但是在多维度方面还未能找到。请问如何解决这个问题?

1D能量距离 1D Wasserstein距离

2个回答

4
您可以使用geomlossdcor包来更加普遍地实现Wasserstein和Energy距离。 geomloss还提供了广泛的其他距离,例如hausdorff、energy、高斯和laplacian距离。默认情况下,它还使用基于pytorch的张量框架,根据输入数据的体积使用不同的后端。 dcor主要使用scipy.spatial.distance.pdistscipy.spatial.distance.cdist计算能量距离。
以下是1D、2D和3D距离计算的几个示例:
# create random 3D data for the test
import torch
torch.random.manual_seed(0)
X = torch.rand((3,100))
Y = torch.rand((3,100))

Energy Distance

# energy distance with geomloss 
from geomloss import SamplesLoss
Loss =  SamplesLoss("energy")

# 3D tensors
Loss( X, Y ).item() 
>>> 0.0063512325286865234

# 2D tensors
Loss( X[:,0:2], Y[:,0:2] ).item() 
>>> 0.005196928977966309

# 1D tensors
Loss( X[:,0,np.newaxis], Y[:,0,np.newaxis] ).item() 
>>> 0.004647582769393921

# energy distance with dcor
import dcor

# 3D tensors
dcor.energy_distance(X,Y)/2
>>> 0.006351688367976838

# 2D tensors
dcor.energy_distance(X[:,0:2], Y[:,0:2])/2
>>> 0.005197086538981377

# 1D tensors
dcor.energy_distance(X[:,0,np.newaxis], Y[:,0,np.newaxis])/2 
>>> 0.004647575813531868

正如您可能已经注意到的那样,我将能量距离除以了二。这是因为geomloss计算的能量距离除以了二,而我想比较两个软件包之间的结果。
原始能量距离: Original Energy Distance 能量距离除以二: Energy Distance divided by two 您还可以查看我的能量距离实现,它与不同的输入维度兼容。它使用Numba编写,可以并行计算并利用可用的硬件提升,在原则上应该可以在GPU上运行,但我没有尝试过。虽然如此,它的执行速度比dcor实现要慢。

Wasserstein Distance

计算Wasserstein距离需要更多参数。Sinkhorn距离是Wasserstein距离的正则化版本,用于近似Wasserstein距离。它也可以看作是Wasserstein和能量距离之间的插值,更多信息请参见这篇论文。原则上,对于接近零的模糊小值,您期望得到Wasserstein距离,而对于较大的值,则得到能量距离,但由于某些实现问题和数值/精度问题,您会在一些较大的值后得到一些负距离值。无论如何,如果您对Wasserstein距离感兴趣,这里有一个例子:
Loss =  SamplesLoss("sinkhorn", blur=0.05,)
Loss( X, Y ).item()
>>> 0.01524302177131176

Loss( X[:,0:2], Y[:,0:2] ).item()
>>> 0.005164701491594315

Loss( X[:,0,np.newaxis], Y[:,0,np.newaxis] ).item()
>>> 0.0018786040600389242

除了模糊度之外,我建议您查看此方法的其他参数,例如pscalingdebias。请注意,此方法的实现与scipy.stats.wasserstein_distance有些不同,如果您要比较两者在1D情况下的差异,请在进行任何比较之前查看文档或代码中的定义!


1
我猜你想测量两个分布之间的距离?即使你的数据是多维的,你也可以通过将数组平铺来推导出每个数组的分布 flat_array1 = array1.flatten()flat_array2 = array2.flatten(),测量每个分布(我的代码是用于累积分布,但你也可以使用高斯分布) - 我在这里的函数中进行了平铺:
`def ecdf(data):
    '''compute eCDF of an image'''
    data_flatten = data.flatten()
    sort_data = np.sort(data_flatten)
    values, bins = np.histogram(sort_data, normed=True)
    cum_data = np.cumsum(values)

    return (bins, cum_data)`

然后测量两个分布之间的距离。

比如说你有两个三维数组,想要测量它们的相似度(或者不相似度,即距离),可以使用上述函数获取分布,然后使用熵、Kullback Liebler或Wasserstein距离。


1
通常来说,采用这种方法时,由于平铺可能会丢失对象的几何形状,这在某些应用程序中可能不被期望,具体取决于距离被使用或解释的方式和位置。 - Novin Shahroudi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接