Simplified _eval_grid_fast

master
Per A Brodtkorb 8 years ago
parent 69a96271f8
commit 8340fe5d76

@ -18,6 +18,7 @@ import numpy as np
import scipy.stats import scipy.stats
from scipy import interpolate, linalg, special from scipy import interpolate, linalg, special
from numpy import pi, sqrt, atleast_2d, exp, meshgrid from numpy import pi, sqrt, atleast_2d, exp, meshgrid
from numpy.fft import fftn, ifftn
from wafo.misc import nextpow2 from wafo.misc import nextpow2
from wafo.containers import PlotData from wafo.containers import PlotData
from wafo.dctpack import dctn, idctn # , dstn, idstn from wafo.dctpack import dctn, idctn # , dstn, idstn
@ -41,6 +42,11 @@ def _assert(cond, msg):
raise ValueError(msg) raise ValueError(msg)
def _assert_warn(cond, msg):
if not cond:
warnings.warn(msg)
def _invnorm(q): def _invnorm(q):
return special.ndtri(q) return special.ndtri(q)
@ -690,27 +696,20 @@ class KDE(_KDE):
h1 = plb.plot(x, f) # 1D probability density plot h1 = plb.plot(x, f) # 1D probability density plot
t = np.trapz(f, x) t = np.trapz(f, x)
""" """
@staticmethod
def _eval_grid_fast(self, *args, **kwds): def _make_grid(dx, d, inc):
X = np.vstack(args)
d, inc = X.shape
dx = X[:, 1] - X[:, 0]
Xn = [] Xn = []
nfft0 = 2 * inc x0 = np.linspace(-inc, inc, 2 * inc + 1)
nfft = (nfft0,) * d
x0 = np.linspace(-inc, inc, nfft0 + 1)
for i in range(d): for i in range(d):
Xn.append(x0[:-1] * dx[i]) Xn.append(x0[:-1] * dx[i])
Xnc = meshgrid(*Xn) # if d > 1 else Xn Xnc = meshgrid(*Xn)
shape0 = Xnc[0].shape
for i in range(d): for i in range(d):
Xnc[i].shape = (-1,) Xnc[i].shape = (-1,)
return Xnc
Xn = np.dot(self._inv_hs, np.vstack(Xnc)) def _kernel_weights(self, Xn, dx, d, inc):
# Obtain the kernel weights. # Obtain the kernel weights.
kw = self.kernel(Xn) kw = self.kernel(Xn)
norm_fact0 = (kw.sum() * dx.prod() * self.n) norm_fact0 = (kw.sum() * dx.prod() * self.n)
@ -723,13 +722,24 @@ class KDE(_KDE):
norm_fact = norm_fact0 norm_fact = norm_fact0
kw = kw / norm_fact kw = kw / norm_fact
return kw
def _eval_grid_fast(self, *args, **kwds):
X = np.vstack(args)
d, inc = X.shape
dx = X[:, 1] - X[:, 0]
Xnc = self._make_grid(dx, d, inc)
Xn = np.dot(self._inv_hs, np.vstack(Xnc))
kw = self._kernel_weights(Xn, dx, d, inc)
r = kwds.get('r', 0) r = kwds.get('r', 0)
if r != 0: if r != 0:
kw *= np.vstack(Xnc) ** r if d > 1 else Xnc[0] ** r kw *= np.vstack(Xnc) ** r if d > 1 else Xnc[0] ** r
shape0 = (2 * inc, ) * d
kw.shape = shape0 kw.shape = shape0
kw = np.fft.ifftshift(kw) kw = np.fft.ifftshift(kw)
fftn = np.fft.fftn
ifftn = np.fft.ifftn
y = kwds.get('y', 1.0) y = kwds.get('y', 1.0)
if self.alpha > 0: if self.alpha > 0:
@ -738,14 +748,7 @@ class KDE(_KDE):
# Find the binned kernel weights, c. # Find the binned kernel weights, c.
c = gridcount(self.dataset, X, y=y) c = gridcount(self.dataset, X, y=y)
# Perform the convolution. # Perform the convolution.
z = np.real(ifftn(fftn(c, s=nfft) * fftn(kw))) z = np.real(ifftn(fftn(c, s=shape0) * fftn(kw)))
# opt = dict(type=1, norm=None)
# z = idctn(dctn(c, shape=(inc,)*d, **opt) * dctn(kw[:inc], **opt),
# **opt)/(inc-1)/2
# # if r is odd
# op2 = dict(type=3, norm=None)
# z3 = idstn(dctn(c, shape=(inc,)*d, **op2) * dstn(kw[1:inc+1], **op2),
# **op2)/(inc-1)/2
ix = (slice(0, inc),) * d ix = (slice(0, inc),) * d
if r == 0: if r == 0:

@ -294,7 +294,7 @@ class _Kernel(object):
def get_ste_constant(self, n): def get_ste_constant(self, n):
mu2, R = self.stats[:2] mu2, R = self.stats[:2]
return R / (mu2 ** (2) * n) return R / (n * mu2 ** 2)
def get_amise_constant(self, n): def get_amise_constant(self, n):
# R= int(mkernel(x)^2), mu2= int(x^2*mkernel(x)) # R= int(mkernel(x)^2), mu2= int(x^2*mkernel(x))
@ -572,9 +572,6 @@ class Kernel(object):
""" """
return self.kernel.stats return self.kernel.stats
# def deriv4_6_8_10(self, t, numout=4):
# return self.kernel.deriv4_6_8_10(t, numout)
def effective_support(self): def effective_support(self):
return self.kernel.effective_support() return self.kernel.effective_support()
@ -749,8 +746,8 @@ class Kernel(object):
cov_a = np.cov(a) cov_a = np.cov(a)
return scale * linalg.sqrtm(cov_a).real * n ** (-1. / (d + 4)) return scale * linalg.sqrtm(cov_a).real * n ** (-1. / (d + 4))
def _get_g(self, k_order_2, psi_order, n, order): @staticmethod
mu2 = _GAUSS_KERNEL.stats[0] def _get_g(k_order_2, mu2, psi_order, n, order):
return (-2. * k_order_2 / (mu2 * psi_order * n)) ** (1. / (order+1)) return (-2. * k_order_2 / (mu2 * psi_order * n)) ** (1. / (order+1))
def hste(self, data, h0=None, inc=128, maxit=100, releps=0.01, abseps=0.0): def hste(self, data, h0=None, inc=128, maxit=100, releps=0.01, abseps=0.0):
@ -813,8 +810,8 @@ class Kernel(object):
psi8NS = _GAUSS_KERNEL.psi(8, s) psi8NS = _GAUSS_KERNEL.psi(8, s)
k40, k60 = _GAUSS_KERNEL.deriv4_6_8_10(0, numout=2) k40, k60 = _GAUSS_KERNEL.deriv4_6_8_10(0, numout=2)
g1 = self._get_g(k40, psi6NS, n, order=6) g1 = self._get_g(k40, mu2, psi6NS, n, order=6)
g2 = self._get_g(k60, psi8NS, n, order=8) g2 = self._get_g(k60, mu2, psi8NS, n, order=8)
psi4 = self._estimate_psi(c, xn, g1, n, order=4) psi4 = self._estimate_psi(c, xn, g1, n, order=4)
psi6 = self._estimate_psi(c, xn, g2, n, order=6) psi6 = self._estimate_psi(c, xn, g2, n, order=6)
@ -917,10 +914,6 @@ class Kernel(object):
break break
else: else:
ai = bi ai = bi
# y = np.asarray([fun(j) for j in x])
# plt.figure(1)
# plt.plot(x,y)
# plt.show()
# use fzero to solve the equation t=zeta*gamma^[5](t) # use fzero to solve the equation t=zeta*gamma^[5](t)
try: try:
@ -996,8 +989,6 @@ class Kernel(object):
h = np.asarray(h0, dtype=float) h = np.asarray(h0, dtype=float)
nfft = inc * 2
ax1, bx1 = self._get_grid_limits(A) ax1, bx1 = self._get_grid_limits(A)
for dim in range(d): for dim in range(d):
@ -1022,7 +1013,7 @@ class Kernel(object):
kw4 = self.kernel(xn / h1) / (n * h1 * self.norm_factor(d=1)) kw4 = self.kernel(xn / h1) / (n * h1 * self.norm_factor(d=1))
kw = np.r_[kw4, 0, kw4[-1:0:-1]] # Apply 'fftshift' to kw. kw = np.r_[kw4, 0, kw4[-1:0:-1]] # Apply 'fftshift' to kw.
f = np.real(ifft(fft(c, nfft) * fft(kw))) # convolution. f = np.real(ifft(fft(c, 2*inc) * fft(kw))) # convolution.
# Estimate psi4=R(f'') using simple finite differences and # Estimate psi4=R(f'') using simple finite differences and
# quadrature. # quadrature.
@ -1113,12 +1104,13 @@ class Kernel(object):
hvec = hvec * (ste_constant2 / ste_constant) ** (1. / 5.) hvec = hvec * (ste_constant2 / ste_constant) ** (1. / 5.)
k40, k60, k80, k100 = _GAUSS_KERNEL.deriv4_6_8_10(0, numout=4) k40, k60, k80, k100 = _GAUSS_KERNEL.deriv4_6_8_10(0, numout=4)
mu2 = _GAUSS_KERNEL.stats[0]
# psi8 = _GAUSS_KERNEL.psi(8) # psi8 = _GAUSS_KERNEL.psi(8)
# psi12 = _GAUSS_KERNEL.psi(12) # psi12 = _GAUSS_KERNEL.psi(12)
psi8 = 105 / (32 * sqrt(pi)) psi8 = 105 / (32 * sqrt(pi))
psi12 = 3465. / (512 * sqrt(pi)) psi12 = 3465. / (512 * sqrt(pi))
g1 = self._get_g(k60, psi8, n, order=8) g1 = self._get_g(k60, mu2, psi8, n, order=8)
g2 = self._get_g(k100, psi12, n, order=12) g2 = self._get_g(k100, mu2, psi12, n, order=12)
for dim in range(d): for dim in range(d):
s = sigmaA[dim] s = sigmaA[dim]
@ -1134,8 +1126,8 @@ class Kernel(object):
psi6 = self._estimate_psi(c, xn, g1, n, order=6) psi6 = self._estimate_psi(c, xn, g1, n, order=6)
psi10 = self._estimate_psi(c, xn, g2, n, order=10) psi10 = self._estimate_psi(c, xn, g2, n, order=10)
g3 = self._get_g(k40, psi6, n, order=6) g3 = self._get_g(k40, mu2, psi6, n, order=6)
g4 = self._get_g(k80, psi10, n, order=10) g4 = self._get_g(k80, mu2, psi10, n, order=10)
psi4 = self._estimate_psi(c, xn, g3, n, order=4) psi4 = self._estimate_psi(c, xn, g3, n, order=4)
psi8 = self._estimate_psi(c, xn, g4, n, order=8) psi8 = self._estimate_psi(c, xn, g4, n, order=8)
@ -1218,6 +1210,7 @@ class Kernel(object):
sigmaA = self.hns(A) / amise_constant sigmaA = self.hns(A) / amise_constant
ax1, bx1 = self._get_grid_limits(A) ax1, bx1 = self._get_grid_limits(A)
mu2 = _GAUSS_KERNEL.stats[0]
h = np.zeros(d) h = np.zeros(d)
for dim in range(d): for dim in range(d):
@ -1238,7 +1231,7 @@ class Kernel(object):
# L-stage iterations to estimate PSI_4 # L-stage iterations to estimate PSI_4
for ix in range(L, 0, -1): for ix in range(L, 0, -1):
gi = self._get_g(Kd[ix - 1], psi, n, order=2*ix + 4) gi = self._get_g(Kd[ix - 1], mu2, psi, n, order=2*ix + 4)
psi = self._estimate_psi(c, xn, gi, n, order=2*ix+2) psi = self._estimate_psi(c, xn, gi, n, order=2*ix+2)
h[dim] = (ste_constant / psi) ** (1. / 5) h[dim] = (ste_constant / psi) ** (1. / 5)
return h return h
@ -1251,50 +1244,50 @@ class Kernel(object):
__call__ = eval_points __call__ = eval_points
# def mkernel(X, kernel): def mkernel(X, kernel):
# """MKERNEL Multivariate Kernel Function. """MKERNEL Multivariate Kernel Function.
#
# Paramaters Paramaters
# ---------- ----------
# X : array-like X : array-like
# matrix size d x n (d = # dimensions, n = # evaluation points) matrix size d x n (d = # dimensions, n = # evaluation points)
# kernel : string kernel : string
# defining kernel defining kernel
# 'epanechnikov' - Epanechnikov kernel. 'epanechnikov' - Epanechnikov kernel.
# 'biweight' - Bi-weight kernel. 'biweight' - Bi-weight kernel.
# 'triweight' - Tri-weight kernel. 'triweight' - Tri-weight kernel.
# 'p1epanechnikov' - product of 1D Epanechnikov kernel. 'p1epanechnikov' - product of 1D Epanechnikov kernel.
# 'p1biweight' - product of 1D Bi-weight kernel. 'p1biweight' - product of 1D Bi-weight kernel.
# 'p1triweight' - product of 1D Tri-weight kernel. 'p1triweight' - product of 1D Tri-weight kernel.
# 'triangular' - Triangular kernel. 'triangular' - Triangular kernel.
# 'gaussian' - Gaussian kernel 'gaussian' - Gaussian kernel
# 'rectangular' - Rectangular kernel. 'rectangular' - Rectangular kernel.
# 'laplace' - Laplace kernel. 'laplace' - Laplace kernel.
# 'logistic' - Logistic kernel. 'logistic' - Logistic kernel.
# Note that only the first 4 letters of the kernel name is needed. Note that only the first 4 letters of the kernel name is needed.
#
# Returns Returns
# ------- -------
# z : ndarray z : ndarray
# kernel function values evaluated at X kernel function values evaluated at X
#
# See also See also
# -------- --------
# KDE KDE
#
# References References
# ---------- ----------
# B. W. Silverman (1986) B. W. Silverman (1986)
# 'Density estimation for statistics and data analysis' 'Density estimation for statistics and data analysis'
# Chapman and Hall, pp. 43, 76 Chapman and Hall, pp. 43, 76
#
# Wand, M. P. and Jones, M. C. (1995) Wand, M. P. and Jones, M. C. (1995)
# 'Density estimation for statistics and data analysis' 'Density estimation for statistics and data analysis'
# Chapman and Hall, pp 31, 103, 175 Chapman and Hall, pp 31, 103, 175
#
# """ """
# fun = _MKERNEL_DICT[kernel[:4]] fun = _MKERNEL_DICT[kernel[:4]]
# return fun(np.atleast_2d(X)) return fun(np.atleast_2d(X))
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save