Added method decorator for numpy trans

parent fcdd2af5
......@@ -54,6 +54,7 @@ from .kernels import normal_kernel1d
from . import kde_methods
from .kde_bandwidth import variance_bandwidth, silverman_covariance, scotts_covariance, botev_bandwidth
from scipy import stats, optimize
from .utils import numpy_method_idx
class KDE1D(object):
r"""
......@@ -339,7 +340,7 @@ class KDE1D(object):
Compute the PDF of the distribution on the set of points ``points``
"""
self.fit_if_needed()
return self._method.pdf(self, np.atleast_1d(points), out)
return self._method.pdf(self, points, out)
def evaluate(self, points, out=None):
"""
......@@ -347,12 +348,14 @@ class KDE1D(object):
"""
return self.pdf(points, out)
@numpy_method_idx
def __call__(self, points, out=None):
"""
This method is an alias for :py:meth:`BoundedKDE1D.evaluate`
"""
return self.pdf(points, out=out)
@numpy_method_idx
def cdf(self, points, out=None):
r"""
Compute the cumulative distribution function defined as:
......@@ -365,7 +368,7 @@ class KDE1D(object):
:math:`p` the density of probability.
"""
self.fit_if_needed()
return self.method.cdf(self, np.atleast_1d(points), out)
return self.method.cdf(self, points, out)
def cdf_grid(self, N=None, cut=None):
"""
......@@ -374,12 +377,13 @@ class KDE1D(object):
self.fit_if_needed()
return self.method.cdf_grid(self, N, cut)
@numpy_method_idx
def icdf(self, points, out=None):
r"""
Compute the inverse cumulative distribution (quantile) function.
"""
self.fit_if_needed()
return self.method.icdf(self, np.atleast_1d(points), out)
return self.method.icdf(self, points, out)
def icdf_grid(self, N=None, cut=None):
"""
......@@ -388,6 +392,7 @@ class KDE1D(object):
self.fit_if_needed()
return self.method.icdf_grid(self, N, cut)
@numpy_method_idx
def sf(self, points, out=None):
r"""
Compute the survival function.
......@@ -403,7 +408,7 @@ class KDE1D(object):
"""
self.fit_if_needed()
return self.method.sf(self, np.atleast_1d(points), out)
return self.method.sf(self, points, out)
def sf_grid(self, N=None, cut=None):
r"""
......@@ -412,6 +417,7 @@ class KDE1D(object):
self.fit_if_needed()
return self.method.sf_grid(self, N, cut)
@numpy_method_idx
def isf(self, points, out=None):
r"""
Compute the inverse survival function, defined as:
......@@ -421,8 +427,7 @@ class KDE1D(object):
isf(p) = \sup\left\{x\in\mathbb{R} : sf(x) \leq p\right\}
"""
self.fit_if_needed()
return self.method.isf(self, np.atleast_1d(points), out)
return self.method.isf(self, points, out)
def isf_grid(self, N=None, cut=None):
r"""
......@@ -431,6 +436,7 @@ class KDE1D(object):
self.fit_if_needed()
return self.method.isf_grid(self, N, cut)
@numpy_method_idx
def hazard(self, points, out=None):
r"""
Compute the hazard function evaluated on the points.
......@@ -442,7 +448,7 @@ class KDE1D(object):
h(x) = \frac{p(x)}{sf(x)}
"""
self.fit_if_needed()
return self.method.hazard(self, np.atleast_1d(points), out)
return self.method.hazard(self, points, out)
def hazard_grid(self, N=None, cut=None):
"""
......@@ -451,6 +457,7 @@ class KDE1D(object):
self.fit_if_needed()
return self.method.hazard_grid(self, N, cut)
@numpy_method_idx
def cumhazard(self, points, out=None):
r"""
Compute the cumulative hazard function evaluated on the points.
......@@ -465,7 +472,7 @@ class KDE1D(object):
function and :math:`sf` the survival function.
"""
self.fit_if_needed()
return self.method.cumhazard(self, np.atleast_1d(points), out)
return self.method.cumhazard(self, points, out)
def cumhazard_grid(self, N=None, cut=None):
"""
......
......@@ -161,12 +161,14 @@ class TestISF(kde_utils.KDETester):
sf = np.linspace(0, 1, 64)
sf_xs = k.isf(sf)
cdf_xs = k.icdf(1-sf)
np.testing.assert_allclose(sf_xs, cdf_xs, method.accuracy, method.accuracy)
acc = max(method.accuracy, method.normed_accuracy)
np.testing.assert_allclose(sf_xs, cdf_xs, acc, acc)
def grid_method_works(self, k, method, name):
comp_sf, xs = k.isf_grid()
ref_sf = k.sf(xs)
np.testing.assert_allclose(comp_sf, ref_sf, 0.03, 0.03)
acc = max(method.grid_accuracy, method.normed_accuracy)
np.testing.assert_allclose(comp_sf, ref_sf, acc, acc)
def kernel_works(self, ker, name):
pass
......@@ -191,12 +193,14 @@ class TestICDF(kde_utils.KDETester):
quant = np.linspace(0, 1, 64)
xs = k.icdf(quant)
cdf_quant = k.cdf(xs)
np.testing.assert_allclose(cdf_quant, quant, method.accuracy, method.accuracy)
acc = max(method.accuracy, method.normed_accuracy)
np.testing.assert_allclose(cdf_quant, quant, acc, acc)
def grid_method_works(self, k, method, name):
comp_cdf, xs = k.icdf_grid()
ref_cdf = k.cdf(xs)
np.testing.assert_allclose(comp_cdf, ref_cdf, method.grid_accuracy, method.grid_accuracy)
acc = max(method.grid_accuracy, method.normed_accuracy)
np.testing.assert_allclose(comp_cdf, ref_cdf, acc, acc)
def kernel_works(self, ker, name):
pass
......
......@@ -96,6 +96,37 @@ def numpy_trans_idx(fct):
return out
return f
def numpy_method_idx(fct):
"""
Decorator to create a function taking a single array-like argument and
return a numpy array of same shape. In addition, if the input as no
dimension, the function will still receive a 1D array, allowing for
indexing.
The function is called as:
fct(self, z, out=out)
This decorator garanties that z and out are at least 1D ndarray of same
shape and out is at least a float.
It also ensure the output is the shape of the initial input (even if it has
no dimension)
"""
def f(self, z, out=None):
z = np.asanyarray(z)
real_shape = z.shape
if len(real_shape) == 0:
z = z.reshape(1)
if out is None:
out = np.empty(z.shape, dtype=type(z.dtype.type() + 0.))
else:
out.shape = z.shape
out = fct(self, z, out=out)
out.shape = real_shape
return out
return f
def namedtuple(typename, field_names, verbose=False, rename=False):
"""Returns a new subclass of tuple with named fields.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment