Python sicpy interp1d更精确
我试图实现一个非参数的KL散度估计,如图所示 这是我的密码:Python sicpy interp1d更精确,python,scipy,Python,Scipy,我试图实现一个非参数的KL散度估计,如图所示 这是我的密码: import numpy as np import math import itertools import random from scipy.interpolate import interp1d def log(x): if x > 0: return math.log(x) else: return 0 g = lambda x, inp,N : sum(0.5 + 0.5 * np.sign(x-i
import numpy as np
import math
import itertools
import random
from scipy.interpolate import interp1d
def log(x):
if x > 0: return math.log(x)
else: return 0
g = lambda x, inp,N : sum(0.5 + 0.5 * np.sign(x-inp))/N
def ecdf(x,N):
out = [g(i,x,N) for i in x]
fun = interp1d(x, out, kind='linear', bounds_error = False, fill_value = (0,1))
return fun
def KL_est(x,y):
ex = min(np.diff(sorted(np.unique(x))))
ey = min(np.diff(sorted(np.unique(y))))
e = min(ex,ey) * 0.9
N = len(x)
x.sort()
y.sort()
P = ecdf(x,N)
Q = ecdf(y,N)
KL = sum(log(v) for v in ((P(x)-P(x-e))/(Q(x)-Q(x-e))) ) / N
return KL
我的问题是scipy interp1d。我使用interp1d返回的函数来查找新输入的值。问题是,一些输入值非常接近(相隔10^-5),函数返回的值与这两个值相同。在我上面的代码中,Q(x)-Q(x-e)导致被零除的错误
下面是一些重现问题的测试代码:
x = np.random.normal(0, 1, 10)
y = np.random.normal(0, 1, 10)
ex = min(np.diff(sorted(np.unique(x))))
ey = min(np.diff(sorted(np.unique(y))))
e = min(ex,ey) * 0.9
N = len(x)
x.sort()
y.sort()
P = ecdf(x,N)
Q = ecdf(y,N)
KL = sum(log(v) for v in ((P(x)-P(x-e))/(Q(x)-Q(x-e))) ) / N
如何获得更精确的插值?随着
e
变得越来越小,您正在有效地计算p
和Q
的导数的比率。正如您所发现的,以这种方式进行浮点运算时,精度很快就会耗尽
另一种方法是使用可以直接返回导数的插值函数。例如,你可以试试。你说的是
kind='linear'
到interp1d
,因此等价物是k=1
。构造样条曲线后,样条曲线的方法将为您提供不同点的所有导数。对于e
的较小值,您可以切换到使用导数。当e
变小时,您将有效地尝试以数字方式计算p
和Q
的导数比率。正如您所发现的,以这种方式进行浮点运算时,精度很快就会耗尽
另一种方法是使用可以直接返回导数的插值函数。例如,你可以试试。你说的是kind='linear'
到interp1d
,因此等价物是k=1
。构造样条曲线后,样条曲线的方法将为您提供不同点的所有导数。对于e
的小值,可以切换到使用导数