【问题标题】:Is there a way to measure the distance between two distributions in a multidimensional space in python?有没有办法测量python中多维空间中两个分布之间的距离?
【发布时间】:2019-06-29 19:02:09
【问题描述】:

我想测量多维空间中两个分布之间的距离。

例如,我想在多个维度上进行诸如 Wasserstein 分布或能量距离之类的测量,而不是一维比较。

我找到了一维的包裹,但我仍然找到了多维的包裹。 我怎样才能摆脱困境?

1D energy distance 1D Wasserstein distance

【问题讨论】:

    标签: python scipy distance distribution


    【解决方案1】:

    您可以分别使用 geomlossdcor 包来更一般地实现 Wasserstein 和能量距离。 geomloss 还提供了范围广泛的其他距离,例如 hausdorff、能量、高斯和拉普拉斯距离。它还根据输入数据的大小使用不同的后端,默认使用基于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 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 计算能量距离除以二,我想比较两个包之间的结果。

    你也可以看看my implementation的能量距离是兼容不同输入维度的。它是使用 Numba 编写的,它可以并行化计算并使用可用的硬件提升,原则上应该可以在 GPU 上运行它,但我还没有尝试过。尽管它的执行速度比dcor 实现要慢。

    Wasserstein 距离

    使用更多参数计算 Wasserstein 距离有点进化。 Sinkhorn 距离是 Wasserstein 距离的正则化版本,程序包使用它来近似 Wasserstein 距离。它也可以看作是 Wasserstein 和能量距离之间的插值,更多信息请参见 this paper。原则上,对于接近于零的小模糊值,您会期望得到 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
    

    除了blur,我建议查看此方法的其他参数,例如pscalingdebias。请注意,此方法的实现与 scipy.stats.wasserstein_distance 略有不同,您可能需要先查看文档或代码中的定义,然后再对 1D 情况进行两者之间的比较!

    【讨论】:

      【解决方案2】:

      我想你还是想测量两个分布之间的距离?即使您的数据是多维的,您也可以通过展平数组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)`
      

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

      假设您有两个 3D 数组并且您想测量相似度(或相异度,即距离),您可以使用上述函数检索分布,然后使用熵、Kullback Liebler 或 Wasserstein 距离。

      【讨论】:

      • 一般来说,使用这种方法,对象的部分几何形状可能会由于展平而丢失,这在某些应用中可能不需要,具体取决于使用或解释距离的位置和方式。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-13
      • 1970-01-01
      • 2017-06-09
      • 2022-08-14
      • 2012-04-20
      • 1970-01-01
      相关资源
      最近更新 更多