Python中的1D Wasserstein距离

Python中的1D Wasserstein距离,python,scipy,statistics,transport,numpy-random,Python,Scipy,Statistics,Transport,Numpy Random,当源分布和目标分布、x和y(也称为边际分布)为1D,即为向量时,下面的公式是Wasserstein距离/最佳传输的特例 其中,F^{-1}是边际u和v的累积分布的逆概率分布函数,从称为x和y的真实数据中导出,这两个数据均由正态分布生成: import numpy as np from numpy.random import randn import scipy.stats as ss n = 100 x = randn(n) y = randn(n) 公式中的积分如何用python和sci

当源分布和目标分布、
x
y
(也称为边际分布)为1D,即为向量时,下面的公式是Wasserstein距离/最佳传输的特例

其中,F^{-1}是边际
u
v
的累积分布的逆概率分布函数,从称为
x
y
的真实数据中导出,这两个数据均由正态分布生成:

import numpy as np
from numpy.random import randn
import scipy.stats as ss

n = 100
x = randn(n)
y = randn(n)
公式中的积分如何用python和scipy编码?我猜x和y必须转换成排序的边缘,它们是非负的,和为1,而Scipy的
ppf
可以用来计算逆的F^{-1}

注意,当n变大时,n个样本的排序集接近1/n,2/n,…,n/n采样的逆CDF。例如:

将numpy导入为np
将matplotlib.pyplot作为plt导入
从scipy.stats导入norm
plt.plot(norm.ppf(np.linspace(0,1,1000)),label=“invcdf”)
plt.plot(np.sort(np.random.normal(size=1000)),label=“sortsample”)
plt.legend()
plt.show()

还要注意,从0到1的积分可以近似为1/n,2/n,…,n/n的和

因此,我们可以简单地回答您的问题:

def W(p, u, v):
    assert len(u) == len(v)
    return np.mean(np.abs(np.sort(u) - np.sort(v))**p)**(1/p)
请注意,如果
len(u)!=len(v)
您仍然可以使用线性插值的方法:

def W(p,u,v):
u=np.排序(u)
v=np.排序(v)
如果len(u)!=len(v):
如果len(u)>len(v):u,v=v,u
us=np.linspace(0,1,len(u))
vs=np.linspace(0,1,len(v))
u=np.linalg.interp(u,us,vs)
返回np.平均值(np.绝对值(u-v)**p)**(1/p)

如果您有关于数据分布类型的先验信息,但没有其参数,则另一种方法是找到数据上的最佳拟合分布(例如使用
scipy.stats.norm.fit
)以计算
u
v
,然后以所需的精度进行积分。例如:

from scipy.stats import norm as gauss
def W_gauss(p, u, v, num_steps):
    ud = gauss(*gauss.fit(u))
    vd = gauss(*gauss.fit(v))
    z = np.linspace(0, 1, num_steps, endpoint=False) + 1/(2*num_steps)
    return np.mean(np.abs(ud.ppf(z) - vd.ppf(z))**p)**(1/p)

积分是和的一种表示形式,因此您应该将其表示为求和,并使用尽可能小的
dz
。查阅一本与数学方法有关的书,你可能会发现这个积分的更好的表示形式。我使用
W(1,u,v)
比较了上面的第二个代码片段,其中
u
v
是用
norm.rvs
生成的向量,但是当我将此函数的结果与
scipy.stats.wasserstein_distance(u,v)
进行比较时,您的函数将后者的输出乘以
1000
。例如,
W
将给出
120
如果
wasserstein_distance
给出
0.12
对于上面的最后一个代码段,函数
W_gauss
返回
nan
作为输出值,并且错误
运行时警告:在减法返回np.linalg.norm(ud.ppf(z)-vd.ppf(z),ord=p)中遇到无效值
。什么是
num_steps
以及应该如何设置它?@develist啊,问题是
gauss.ppf
0
1
处(正确地)是无限的。我会解决的
num_steps
只是一个整数参数,表示在计算积分时应该使用多少步,精度越高。你知道为什么(第一个)函数
W
在我最新版本的测试中没有返回与
wasserstein_distance
?@develist相同的结果吗(请确保您包含了我的编辑)我们有
W(1,u,v)
匹配
scipy.stats.wasserstein\u距离(u,v)
。确保您与
np.isclose
进行比较,而不是与
=
进行比较,因为浮点不是完美的。