2017-07-11 10 views
0

私はここでは、このpaperより精度

に示す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-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 

にはどうすれば、より正確な補間を取得しに行きますか?

答えて

1

eが小さくなると、実際にはPQの導関数の比を数値的に計算しようとしています。あなたが探しているように、あなたは浮動小数点でこのようにして本当に素早く精度を使い果たします。

代わりの方法として、導関数を直接返す補間関数を使用する方法があります。たとえば、scipy.interpolate.InterpolatedUnivariateSplineを試すことができます。 kind='linear'interp1dと言っていたので、相当するのはk=1です。一旦それを構築すると、スプラインにはすべての派生物を異なる点で与える方法derivatives()があります。 eの小さな値の場合は、微係数を使用するように切り替えることができます。

+0

恐ろしい!それは完璧に働いた。助けてくれてありがとう! – darkyoda182