请注意,当n变大时,我们有一组已排序的n 个样本接近以 1/n、2/n、...、n/n 采样的逆 CDF。例如:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import 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.sort(u)
v = np.sort(v)
if len(u) != len(v):
if 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)
return np.mean(np.abs(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)