diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..fb90c2c7 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +joe.py \ No newline at end of file diff --git a/.idea/Copulas.iml b/.idea/Copulas.iml new file mode 100644 index 00000000..3ed51aed --- /dev/null +++ b/.idea/Copulas.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 00000000..105ce2da --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..55d79d65 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..0cc68576 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/copulas/bivariate/__init__.py b/copulas/bivariate/__init__.py index dafbc821..70a65724 100644 --- a/copulas/bivariate/__init__.py +++ b/copulas/bivariate/__init__.py @@ -8,6 +8,7 @@ from copulas.bivariate.clayton import Clayton from copulas.bivariate.frank import Frank from copulas.bivariate.gumbel import Gumbel +from copulas.bivariate.joe import Joe from copulas.bivariate.utils import split_matrix __all__ = ( @@ -16,6 +17,7 @@ 'CopulaTypes', 'Frank', 'Gumbel', + 'Joe' ) @@ -96,8 +98,13 @@ def _compute_candidates(copulas, left_tail, right_tail): X_right = np.column_stack((right_tail, right_tail)) for copula in copulas: - left.append(copula.cumulative_distribution(X_left) / np.power(left_tail, 2)) - right.append(_compute_tail(copula.cumulative_distribution(X_right), right_tail)) + if isinstance(copula, Joe): + # Compute dependencies for Joe copula + left.append(...) + right.append(...) + else: + left.append(copula.cumulative_distribution(X_left) / np.power(left_tail, 2)) + right.append(_compute_tail(copula.cumulative_distribution(X_right), right_tail)) return left, right @@ -140,7 +147,7 @@ def select_copula(X): copula_candidates = [frank] # append copulas into the candidate list - for copula_class in [Clayton, Gumbel]: + for copula_class in [Clayton, Gumbel, Joe]: try: copula = copula_class() copula.tau = frank.tau diff --git a/copulas/bivariate/joe.py b/copulas/bivariate/joe.py new file mode 100644 index 00000000..387e7a88 --- /dev/null +++ b/copulas/bivariate/joe.py @@ -0,0 +1,87 @@ +import numpy as np +from copulas.bivariate.base import Bivariate, CopulaTypes +from copulas.bivariate.utils import split_matrix + +class Joe(Bivariate): + """Class for Joe copula model.""" + + copula_type = CopulaTypes.JOE + theta_interval = [0, float('inf')] + invalid_thetas = [0] + + def __init__(self, theta=1): + """ + Initialize a Joe copula. + + Parameters: + - theta (float): The theta parameter of the Joe copula. Default is 1. + """ + self.theta = theta + + def generator(self, t): + """ + Compute the generator function of the Joe copula. + + The generator function of the Joe copula is defined as: + + .. math:: G(t) = -((1 - t^(-theta))^(-1/theta)) + + Parameters: + - t (float or np.array): The value(s) at which to evaluate the generator. + + Returns: + - float or np.array: The value(s) of the generator function at t. + """ + return -((1 - t ** (-self.theta)) ** (1 / self.theta)) + + def pdf(self, X): + """ + Compute the probability density function for the Joe copula. + + The probability density function (PDF) for the Joe copula is given by: + + .. math:: c(u, v) = (theta - 1) * (u^(-theta) + v^(-theta) - 1)^(theta - 2) * u^(-theta - 1) * v^(-theta - 1) + + Parameters: + - X (np.array): The input array of shape (n, 2) containing pairs of values (u, v). + + Returns: + - np.array: The probability density values for each pair in X. + """ + U, V = split_matrix(X) + return (self.theta - 1) * (U ** (-self.theta) + V ** (-self.theta) - 1) ** (self.theta - 2) * U ** (-self.theta - 1) * V ** (-self.theta - 1) + + def cdf(self, X): + """ + Compute the cumulative distribution function for the Joe copula. + + The cumulative distribution function (CDF) for the Joe copula is given by: + + .. math:: C(u, v) = (u^(-theta) + v^(-theta) - 1)^theta + + Parameters: + - X (np.array): The input array of shape (n, 2) containing pairs of values (u, v). + + Returns: + - np.array: The cumulative distribution values for each pair in X. + """ + U, V = split_matrix(X) + return (U ** (-self.theta) + V ** (-self.theta) - 1) ** self.theta + + def percent_point(self, y, V): + """ + Compute the inverse of conditional cumulative distribution :math:`C(u|v)^{-1}`. + + The inverse of conditional cumulative distribution :math:`C(u|v)^{-1}` for the Joe copula + is given by: + + .. math:: (y^(1/theta) + v^(-theta) - 1)^(-1/theta) + + Parameters: + - y (float or np.array): The value(s) of :math:`C(u|v)`. + - V (float or np.array): The given value(s) of v. + + Returns: + - float or np.array: The inverse of conditional cumulative distribution values. + """ + return (y ** (1 / self.theta) + V ** (-self.theta) - 1) ** (-1 / self.theta)