"""
Created on Fri Jan 29 19:19:45 2021
Author: Josef Perktold
License: BSD-3
"""
from statsmodels.compat.pandas import deprecate_kwarg
import numpy as np
from scipy import stats
from statsmodels.distributions.copula.copulas import Copula
from statsmodels.tools.rng_qrng import check_random_state
[docs]
class IndependenceCopula(Copula):
"""Independence copula.
Copula with independent random variables.
.. math::
C_\theta(u,v) = uv
Parameters
----------
k_dim : int
Dimension, number of components in the multivariate random variable.
Notes
-----
IndependenceCopula does not have copula parameters.
If non-empty ``args`` are provided in methods, then a ValueError is raised.
The ``args`` keyword is provided for a consistent interface across
copulas.
"""
def __init__(self, k_dim=2):
super().__init__(k_dim=k_dim)
def _handle_args(self, args):
if args != () and args is not None:
msg = "Independence copula does not use copula parameters."
raise ValueError(msg)
else:
return args
[docs]
@deprecate_kwarg("random_state", "rng")
def rvs(self, nobs=1, args=(), rng=None):
"""Generate random variates from the copula.
Parameters
----------
nobs : int, optional
Number of samples to generate from the copula. Default is 1.
args : tuple
Arguments for copula parameters. Not used by ``IndependenceCopula``.
rng : {None, int, array_like[int], numpy.random.Generator, numpy.random.RandomState}, optional
If `rng` is None, a new ``Generator`` is created using fresh
entropy from the operating system. If `rng` is an int or array
of ints, a new ``Generator`` is created, seeded with `rng`. If
`rng` is already a ``Generator`` or ``RandomState`` instance,
that instance is used.
random_state : {None, int, array_like[int], numpy.random.Generator, numpy.random.RandomState}, optional
.. deprecated:: 0.15
random_state has been deprecated. In-line with SPEC-007, use
rng for passing a random number generator or seed.
Returns
-------
sample : array_like (nobs, k_dim)
Sample from the copula.
"""
self._handle_args(args)
rng = check_random_state(rng)
x = rng.random((nobs, self.k_dim))
return x
[docs]
def pdf(self, u, args=()):
u = np.asarray(u)
return np.ones(u.shape[:-1])
[docs]
def cdf(self, u, args=()):
return np.prod(u, axis=-1)
[docs]
def tau(self):
return 0
[docs]
def plot_pdf(self, *args):
raise NotImplementedError("PDF is constant over the domain.")
def rvs_kernel(sample, size, bw=1, k_func=None, return_extras=False, rng=None):
"""Random sampling from empirical copula using Beta distribution
Parameters
----------
sample : ndarray
Sample of multivariate observations in (o, 1) interval.
size : int
Number of observations to simulate.
bw : float
Bandwidth for Beta sampling. The beta copula corresponds to a kernel
estimate of the distribution. bw=1 corresponds to the empirical beta
copula. A small bandwidth like bw=0.001 corresponds to small noise
added to the empirical distribution. Larger bw, e.g. bw=10 corresponds
to kernel estimate with more smoothing.
k_func : None or callable
The default kernel function is currently a beta function with 1 added
to the first beta parameter.
return_extras : bool
If this is False, then only the random sample will be returned.
If true, then extra information is returned that is mainly of interest
for verification.
rng : {None, int, array_like[int], numpy.random.Generator, numpy.random.RandomState}, optional
If `rng` is None, a new ``Generator`` is created using fresh
entropy from the operating system. If `rng` is an int or array
of ints, a new ``Generator`` is created, seeded with `rng`. If
`rng` is already a ``Generator`` or ``RandomState`` instance,
that instance is used.
Returns
-------
rvs : ndarray
Multivariate sample with ``size`` observations drawn from the Beta
Copula.
Notes
-----
Status: experimental, API will change.
"""
# vectorized for observations
n = sample.shape[0]
if k_func is None:
kfunc = _kernel_rvs_beta1
rng = check_random_state(rng)
if isinstance(rng, np.random.RandomState):
idx = rng.randint(0, n, size=size)
else:
idx = rng.integers(0, n, size=size)
xi = sample[idx]
krvs = np.column_stack([kfunc(xii, bw) for xii in xi.T])
if return_extras:
return krvs, idx, xi
else:
return krvs
def _kernel_rvs_beta(x, bw):
# Beta kernel for density, pdf, estimation
return stats.beta.rvs(x / bw + 1, (1 - x) / bw + 1, size=x.shape)
def _kernel_rvs_beta1(x, bw):
# Beta kernel for density, pdf, estimation
# Kiriliouk, Segers, Tsukuhara 2020 arxiv, using bandwith 1/nobs sample
return stats.beta.rvs(x / bw, (1 - x) / bw + 1)