Source code for copulas.bivariate.clayton

"""Clayton module."""

import numpy as np

from copulas.bivariate.base import Bivariate, CopulaTypes
from copulas.bivariate.utils import split_matrix


[docs]class Clayton(Bivariate): """Class for clayton copula model.""" copula_type = CopulaTypes.CLAYTON theta_interval = [0, float('inf')] invalid_thetas = []
[docs] def generator(self, t): r"""Compute the generator function for Clayton copula family. The generator is a function :math:`\psi: [0,1]\times\Theta \rightarrow [0, \infty)` # noqa: JS101 that given an Archimedian copula fulfills: .. math:: C(u,v) = \psi^{-1}(\psi(u) + \psi(v)) Args: t (numpy.ndarray) Returns: numpy.ndarray """ self.check_fit() return (1.0 / self.theta) * (np.power(t, -self.theta) - 1)
[docs] def probability_density(self, X): r"""Compute probability density function for given copula family. The probability density(PDF) for the Clayton family of copulas correspond to the formula: .. math:: c(U,V) = \frac{\partial^2}{\partial v \partial u}C(u,v) = (\theta + 1)(uv)^{-\theta-1}(u^{-\theta} + v^{-\theta} - 1)^{-\frac{2\theta + 1}{\theta}} Args: X (numpy.ndarray) Returns: numpy.ndarray: Probability density for the input values. """ self.check_fit() U, V = split_matrix(X) a = (self.theta + 1) * np.power(U * V, -(self.theta + 1)) b = np.power(U, -self.theta) + np.power(V, -self.theta) - 1 c = -(2 * self.theta + 1) / self.theta return a * np.power(b, c)
[docs] def cumulative_distribution(self, X): """Compute the cumulative distribution function for the clayton copula. The cumulative density(cdf), or distribution function for the Clayton family of copulas correspond to the formula: .. math:: C(u,v) = (u^{-θ} + v^{-θ} - 1)^{-1/θ} Args: X (numpy.ndarray) Returns: numpy.ndarray: cumulative probability. """ self.check_fit() U, V = split_matrix(X) if (V == 0).all() or (U == 0).all(): return np.zeros(V.shape[0]) else: cdfs = [ np.power( np.power(U[i], -self.theta) + np.power(V[i], -self.theta) - 1, -1.0 / self.theta ) if (U[i] > 0 and V[i] > 0) else 0 for i in range(len(U)) ] return np.array(cdfs)
[docs] def percent_point(self, y, V): """Compute the inverse of conditional cumulative distribution :math:`C(u|v)^{-1}`. Args: y (numpy.ndarray): Value of :math:`C(u|v)`. v (numpy.ndarray): given value of v. """ self.check_fit() if self.theta < 0: return V else: a = np.power(y, self.theta / (-1 - self.theta)) b = np.power(V, self.theta) # If b == 0, self.theta tends to inf, # so the next operation tends to 1 if (b == 0).all(): return np.ones(len(V)) return np.power((a + b - 1) / b, -1 / self.theta)
[docs] def partial_derivative(self, X): r"""Compute partial derivative of cumulative distribution. The partial derivative of the copula(CDF) is the conditional CDF. .. math:: F(v|u) = \frac{\partial C(u,v)}{\partial u} = u^{- \theta - 1}(u^{-\theta} + v^{-\theta} - 1)^{-\frac{\theta+1}{\theta}} Args: X (np.ndarray) y (float) Returns: numpy.ndarray: Derivatives """ self.check_fit() U, V = split_matrix(X) A = np.power(V, -self.theta - 1) # If theta tends to inf, A tends to inf # And the next partial_derivative tends to 0 if (A == np.inf).any(): return np.zeros(len(V)) B = np.power(V, -self.theta) + np.power(U, -self.theta) - 1 h = np.power(B, (-1 - self.theta) / self.theta) return A * h
[docs] def compute_theta(self): r"""Compute theta parameter using Kendall's tau. On Clayton copula this is .. math:: τ = θ/(θ + 2) \implies θ = 2τ/(1-τ) .. math:: θ ∈ (0, ∞) On the corner case of :math:`τ = 1`, return infinite. """ if self.tau == 1: return np.inf return 2 * self.tau / (1 - self.tau)