copulas 0.12.4.dev3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,163 @@
1
+ """Clayton module."""
2
+
3
+ import numpy as np
4
+
5
+ from copulas.bivariate.base import Bivariate, CopulaTypes
6
+ from copulas.bivariate.utils import split_matrix
7
+
8
+
9
+ class Clayton(Bivariate):
10
+ """Class for clayton copula model."""
11
+
12
+ copula_type = CopulaTypes.CLAYTON
13
+ theta_interval = [0, float('inf')]
14
+ invalid_thetas = []
15
+
16
+ def generator(self, t):
17
+ r"""Compute the generator function for Clayton copula family.
18
+
19
+ The generator is a function
20
+ :math:`\psi: [0,1]\times\Theta \rightarrow [0, \infty)` # noqa: JS101
21
+
22
+ that given an Archimedian copula fulfills:
23
+ .. math:: C(u,v) = \psi^{-1}(\psi(u) + \psi(v))
24
+
25
+ Args:
26
+ t (numpy.ndarray)
27
+
28
+ Returns:
29
+ numpy.ndarray
30
+
31
+ """
32
+ self.check_fit()
33
+
34
+ return (1.0 / self.theta) * (np.power(t, -self.theta) - 1)
35
+
36
+ def probability_density(self, X):
37
+ r"""Compute probability density function for given copula family.
38
+
39
+ The probability density(PDF) for the Clayton family of copulas correspond to the formula:
40
+
41
+ .. math:: c(U,V) = \frac{\partial^2}{\partial v \partial u}C(u,v) =
42
+ (\theta + 1)(uv)^{-\theta-1}(u^{-\theta} +
43
+ v^{-\theta} - 1)^{-\frac{2\theta + 1}{\theta}}
44
+
45
+ Args:
46
+ X (numpy.ndarray)
47
+
48
+ Returns:
49
+ numpy.ndarray: Probability density for the input values.
50
+
51
+ """
52
+ self.check_fit()
53
+
54
+ U, V = split_matrix(X)
55
+
56
+ a = (self.theta + 1) * np.power(U * V, -(self.theta + 1))
57
+ b = np.power(U, -self.theta) + np.power(V, -self.theta) - 1
58
+ c = -(2 * self.theta + 1) / self.theta
59
+ return a * np.power(b, c)
60
+
61
+ def cumulative_distribution(self, X):
62
+ """Compute the cumulative distribution function for the clayton copula.
63
+
64
+ The cumulative density(cdf), or distribution function for the Clayton family of copulas
65
+ correspond to the formula:
66
+
67
+ .. math:: C(u,v) = (u^{-θ} + v^{-θ} - 1)^{-1/θ}
68
+
69
+ Args:
70
+ X (numpy.ndarray)
71
+
72
+ Returns:
73
+ numpy.ndarray: cumulative probability.
74
+
75
+ """
76
+ self.check_fit()
77
+
78
+ U, V = split_matrix(X)
79
+
80
+ if (V == 0).all() or (U == 0).all():
81
+ return np.zeros(V.shape[0])
82
+
83
+ else:
84
+ cdfs = [
85
+ np.power(
86
+ np.power(U[i], -self.theta) + np.power(V[i], -self.theta) - 1,
87
+ -1.0 / self.theta,
88
+ )
89
+ if (U[i] > 0 and V[i] > 0)
90
+ else 0
91
+ for i in range(len(U))
92
+ ]
93
+
94
+ return np.array(cdfs)
95
+
96
+ def percent_point(self, y, V):
97
+ """Compute the inverse of conditional cumulative distribution :math:`C(u|v)^{-1}`.
98
+
99
+ Args:
100
+ y (numpy.ndarray): Value of :math:`C(u|v)`.
101
+ v (numpy.ndarray): given value of v.
102
+ """
103
+ self.check_fit()
104
+
105
+ if self.theta < 0:
106
+ return V
107
+
108
+ else:
109
+ a = np.power(y, self.theta / (-1 - self.theta))
110
+ b = np.power(V, self.theta)
111
+
112
+ # If b == 0, self.theta tends to inf,
113
+ # so the next operation tends to 1
114
+ if (b == 0).all():
115
+ return np.ones(len(V))
116
+
117
+ return np.power((a + b - 1) / b, -1 / self.theta)
118
+
119
+ def partial_derivative(self, X):
120
+ r"""Compute partial derivative of cumulative distribution.
121
+
122
+ The partial derivative of the copula(CDF) is the conditional CDF.
123
+
124
+ .. math:: F(v|u) = \frac{\partial C(u,v)}{\partial u} =
125
+ u^{- \theta - 1}(u^{-\theta} + v^{-\theta} - 1)^{-\frac{\theta+1}{\theta}}
126
+
127
+ Args:
128
+ X (np.ndarray)
129
+ y (float)
130
+
131
+ Returns:
132
+ numpy.ndarray: Derivatives
133
+
134
+ """
135
+ self.check_fit()
136
+
137
+ U, V = split_matrix(X)
138
+
139
+ A = np.power(V, -self.theta - 1)
140
+
141
+ # If theta tends to inf, A tends to inf
142
+ # And the next partial_derivative tends to 0
143
+ if (A == np.inf).any():
144
+ return np.zeros(len(V))
145
+
146
+ B = np.power(V, -self.theta) + np.power(U, -self.theta) - 1
147
+ h = np.power(B, (-1 - self.theta) / self.theta)
148
+ return A * h
149
+
150
+ def compute_theta(self):
151
+ r"""Compute theta parameter using Kendall's tau.
152
+
153
+ On Clayton copula this is
154
+
155
+ .. math:: τ = θ/(θ + 2) \implies θ = 2τ/(1-τ)
156
+ .. math:: θ ∈ (0, ∞)
157
+
158
+ On the corner case of :math:`τ = 1`, return infinite.
159
+ """
160
+ if self.tau == 1:
161
+ return np.inf
162
+
163
+ return 2 * self.tau / (1 - self.tau)
@@ -0,0 +1,170 @@
1
+ """Frank module."""
2
+
3
+ import sys
4
+
5
+ import numpy as np
6
+ import scipy.integrate as integrate
7
+ from scipy.optimize import least_squares
8
+
9
+ from copulas.bivariate.base import Bivariate, CopulaTypes
10
+ from copulas.bivariate.utils import split_matrix
11
+ from copulas.utils import EPSILON
12
+
13
+ MIN_FLOAT_LOG = np.log(sys.float_info.min)
14
+ MAX_FLOAT_LOG = np.log(sys.float_info.max)
15
+
16
+
17
+ class Frank(Bivariate):
18
+ """Class for Frank copula model."""
19
+
20
+ copula_type = CopulaTypes.FRANK
21
+ theta_interval = [-float('inf'), float('inf')]
22
+ invalid_thetas = [0]
23
+
24
+ def generator(self, t):
25
+ """Return the generator function."""
26
+ a = (np.exp(-self.theta * t) - 1) / (np.exp(-self.theta) - 1)
27
+ return -np.log(a)
28
+
29
+ def _g(self, z):
30
+ r"""Assist in solving the Frank copula.
31
+
32
+ This functions encapsulates :math:`g(z) = e^{-\theta z} - 1` used on Frank copulas.
33
+
34
+ Argument:
35
+ z: np.ndarray
36
+
37
+ Returns:
38
+ np.ndarray
39
+
40
+ """
41
+ return np.exp(-self.theta * z) - 1
42
+
43
+ def probability_density(self, X):
44
+ r"""Compute probability density function for given copula family.
45
+
46
+ The probability density(PDF) for the Frank family of copulas correspond to the formula:
47
+
48
+ .. math:: c(U,V) = \frac{\partial^2 C(u,v)}{\partial v \partial u} =
49
+ \frac{-\theta g(1)(1 + g(u + v))}{(g(u) g(v) + g(1)) ^ 2}
50
+
51
+ Where the g function is defined by:
52
+
53
+ .. math:: g(x) = e^{-\theta x} - 1
54
+
55
+ Args:
56
+ X: `np.ndarray`
57
+
58
+ Returns:
59
+ np.array: probability density
60
+
61
+ """
62
+ self.check_fit()
63
+
64
+ U, V = split_matrix(X)
65
+
66
+ if self.theta == 0:
67
+ return U * V
68
+
69
+ else:
70
+ num = (-self.theta * self._g(1)) * (1 + self._g(U + V))
71
+ aux = self._g(U) * self._g(V) + self._g(1)
72
+ den = np.power(aux, 2)
73
+ return num / den
74
+
75
+ def cumulative_distribution(self, X):
76
+ r"""Compute the cumulative distribution function for the Frank copula.
77
+
78
+ The cumulative density(cdf), or distribution function for the Frank family of copulas
79
+ correspond to the formula:
80
+
81
+ .. math:: C(u,v) = −\frac{\ln({\frac{1 + g(u) g(v)}{g(1)}})}{\theta}
82
+
83
+
84
+ Args:
85
+ X: `np.ndarray`
86
+
87
+ Returns:
88
+ np.array: cumulative distribution
89
+
90
+ """
91
+ self.check_fit()
92
+
93
+ U, V = split_matrix(X)
94
+
95
+ num = (np.exp(-self.theta * U) - 1) * (np.exp(-self.theta * V) - 1)
96
+ den = np.exp(-self.theta) - 1
97
+
98
+ return -1.0 / self.theta * np.log(1 + num / den)
99
+
100
+ def percent_point(self, y, V):
101
+ """Compute the inverse of conditional cumulative distribution :math:`C(u|v)^{-1}`.
102
+
103
+ Args:
104
+ y: `np.ndarray` value of :math:`C(u|v)`.
105
+ v: `np.ndarray` given value of v.
106
+ """
107
+ self.check_fit()
108
+
109
+ if self.theta == 0:
110
+ return V
111
+
112
+ else:
113
+ return super().percent_point(y, V)
114
+
115
+ def partial_derivative(self, X):
116
+ r"""Compute partial derivative of cumulative distribution.
117
+
118
+ The partial derivative of the copula(CDF) is the conditional CDF.
119
+
120
+ .. math:: F(v|u) = \frac{\partial}{\partial u}C(u,v) =
121
+ \frac{g(u)g(v) + g(v)}{g(u)g(v) + g(1)}
122
+
123
+ Args:
124
+ X (np.ndarray)
125
+ y (float)
126
+
127
+ Returns:
128
+ np.ndarray
129
+
130
+ """
131
+ self.check_fit()
132
+
133
+ U, V = split_matrix(X)
134
+
135
+ if self.theta == 0:
136
+ return V
137
+
138
+ else:
139
+ num = self._g(U) * self._g(V) + self._g(U)
140
+ den = self._g(U) * self._g(V) + self._g(1)
141
+ return num / den
142
+
143
+ def compute_theta(self):
144
+ r"""Compute theta parameter using Kendall's tau.
145
+
146
+ On Frank copula, the relationship between tau and theta is defined by:
147
+
148
+ .. math:: \tau = 1 − \frac{4}{\theta} + \frac{4}{\theta^2}\int_0^\theta \!
149
+ \frac{t}{e^t -1} \mathrm{d}t.
150
+
151
+ In order to solve it, we can simplify it as
152
+
153
+ .. math:: 0 = 1 + \frac{4}{\theta}(D_1(\theta) - 1) - \tau
154
+
155
+ where the function D is the Debye function of first order, defined as:
156
+
157
+ .. math:: D_1(x) = \frac{1}{x}\int_0^x\frac{t}{e^t -1} \mathrm{d}t.
158
+
159
+ """
160
+ result = least_squares(self._tau_to_theta, 1, bounds=(MIN_FLOAT_LOG, MAX_FLOAT_LOG))
161
+ return result.x[0]
162
+
163
+ def _tau_to_theta(self, alpha):
164
+ """Relationship between tau and theta as a solvable equation."""
165
+
166
+ def debye(t):
167
+ return t / (np.exp(t) - 1)
168
+
169
+ debye_value = integrate.quad(debye, EPSILON, alpha.item())[0] / alpha
170
+ return 4 * (debye_value - 1) / alpha + 1 - self.tau
@@ -0,0 +1,144 @@
1
+ """Gumbel module."""
2
+
3
+ import numpy as np
4
+
5
+ from copulas.bivariate.base import Bivariate, CopulaTypes
6
+ from copulas.bivariate.utils import split_matrix
7
+
8
+
9
+ class Gumbel(Bivariate):
10
+ """Class for clayton copula model."""
11
+
12
+ copula_type = CopulaTypes.GUMBEL
13
+ theta_interval = [1, float('inf')]
14
+ invalid_thetas = []
15
+
16
+ def generator(self, t):
17
+ """Return the generator function."""
18
+ return np.power(-np.log(t), self.theta)
19
+
20
+ def probability_density(self, X):
21
+ r"""Compute probability density function for given copula family.
22
+
23
+ The probability density(PDF) for the Gumbel family of copulas correspond to the formula:
24
+
25
+ .. math::
26
+
27
+ \begin{align}
28
+ c(U,V)
29
+ &= \frac{\partial^2 C(u,v)}{\partial v \partial u}
30
+ &= \frac{C(u,v)}{uv} \frac{((-\ln u)^{\theta} # noqa: JS101
31
+ + (-\ln v)^{\theta})^{\frac{2} # noqa: JS101
32
+ {\theta} - 2 }}{(\ln u \ln v)^{1 - \theta}} # noqa: JS101
33
+ ( 1 + (\theta-1) \big((-\ln u)^\theta
34
+ + (-\ln v)^\theta\big)^{-1/\theta})
35
+ \end{align}
36
+
37
+ Args:
38
+ X (numpy.ndarray)
39
+
40
+ Returns:
41
+ numpy.ndarray
42
+
43
+ """
44
+ self.check_fit()
45
+
46
+ U, V = split_matrix(X)
47
+
48
+ if self.theta == 1:
49
+ return U * V
50
+
51
+ else:
52
+ a = np.power(U * V, -1)
53
+ tmp = np.power(-np.log(U), self.theta) + np.power(-np.log(V), self.theta)
54
+ b = np.power(tmp, -2 + 2.0 / self.theta)
55
+ c = np.power(np.log(U) * np.log(V), self.theta - 1)
56
+ d = 1 + (self.theta - 1) * np.power(tmp, -1.0 / self.theta)
57
+ return self.cumulative_distribution(X) * a * b * c * d
58
+
59
+ def cumulative_distribution(self, X):
60
+ r"""Compute the cumulative distribution function for the Gumbel copula.
61
+
62
+ The cumulative density(cdf), or distribution function for the Gumbel family of copulas
63
+ correspond to the formula:
64
+
65
+ .. math:: C(u,v) = e^{-((-\ln u)^{\theta} + (-\ln v)^{\theta})^{\frac{1}{\theta}}}
66
+
67
+ Args:
68
+ X (np.ndarray)
69
+
70
+ Returns:
71
+ np.ndarray: cumulative probability for the given datapoints, cdf(X).
72
+
73
+ """
74
+ self.check_fit()
75
+
76
+ U, V = split_matrix(X)
77
+
78
+ if self.theta == 1:
79
+ return U * V
80
+
81
+ else:
82
+ h = np.power(-np.log(U), self.theta) + np.power(-np.log(V), self.theta)
83
+ h = -np.power(h, 1.0 / self.theta)
84
+ cdfs = np.exp(h)
85
+ return cdfs
86
+
87
+ def percent_point(self, y, V):
88
+ """Compute the inverse of conditional cumulative distribution :math:`C(u|v)^{-1}`.
89
+
90
+ Args:
91
+ y (np.ndarray): value of :math:`C(u|v)`.
92
+ v (np.ndarray): given value of v.
93
+
94
+ """
95
+ self.check_fit()
96
+
97
+ if self.theta == 1:
98
+ return y
99
+
100
+ else:
101
+ return super().percent_point(y, V)
102
+
103
+ def partial_derivative(self, X):
104
+ r"""Compute partial derivative of cumulative distribution.
105
+
106
+ The partial derivative of the copula(CDF) is the conditional CDF.
107
+
108
+ .. math:: F(v|u) = \frac{\partial C(u,v)}{\partial u} =
109
+ C(u,v)\frac{((-\ln u)^{\theta} + (-\ln v)^{\theta})^{\frac{1}{\theta} - 1}}
110
+ {\theta(- \ln u)^{1 -\theta}}
111
+
112
+ Args:
113
+ X (np.ndarray)
114
+ y (float)
115
+
116
+ Returns:
117
+ numpy.ndarray
118
+
119
+ """
120
+ self.check_fit()
121
+
122
+ U, V = split_matrix(X)
123
+
124
+ if self.theta == 1:
125
+ return V
126
+
127
+ else:
128
+ t1 = np.power(-np.log(U), self.theta)
129
+ t2 = np.power(-np.log(V), self.theta)
130
+ p1 = self.cumulative_distribution(X)
131
+ p2 = np.power(t1 + t2, -1 + 1.0 / self.theta)
132
+ p3 = np.power(-np.log(V), self.theta - 1)
133
+ return p1 * p2 * p3 / V
134
+
135
+ def compute_theta(self):
136
+ r"""Compute theta parameter using Kendall's tau.
137
+
138
+ On Gumbel copula :math:`\tau` is defined as :math:`τ = \frac{θ−1}{θ}`
139
+ that we solve as :math:`θ = \frac{1}{1-τ}`
140
+ """
141
+ if self.tau == 1:
142
+ raise ValueError("Tau value can't be 1")
143
+
144
+ return 1 / (1 - self.tau)
@@ -0,0 +1,81 @@
1
+ """Independence module."""
2
+
3
+ import numpy as np
4
+
5
+ from copulas.bivariate.base import Bivariate, CopulaTypes
6
+ from copulas.bivariate.utils import split_matrix
7
+
8
+
9
+ class Independence(Bivariate):
10
+ """This class represent the copula for two independent variables."""
11
+
12
+ copula_type = CopulaTypes.INDEPENDENCE
13
+
14
+ def fit(self, X):
15
+ """Fit the copula to the given data.
16
+
17
+ Args:
18
+ X (numpy.array): Probabilites in a matrix shaped (n, 2)
19
+
20
+ Returns:
21
+ None
22
+
23
+ """
24
+
25
+ def generator(self, t):
26
+ """Compute the generator function for the Copula.
27
+
28
+ The generator function is a function f(t), such that an archimedian copula can be
29
+ defined as
30
+
31
+ C(u1, ..., uN) = f(f^-1(u1), ..., f^-1(uN)).
32
+
33
+ Args:
34
+ t(numpy.array)
35
+
36
+ Returns:
37
+ np.array
38
+
39
+ """
40
+ return np.log(t)
41
+
42
+ def probability_density(self, X):
43
+ """Compute the probability density for the independence copula."""
44
+ return np.all((0.0 <= X) & (X <= 1.0), axis=1).astype(float)
45
+
46
+ def cumulative_distribution(self, X):
47
+ """Compute the cumulative distribution of the independence bivariate copula is the product.
48
+
49
+ Args:
50
+ X(numpy.array): Matrix of shape (n,2), whose values are in [0, 1]
51
+
52
+ Returns:
53
+ numpy.array: Cumulative distribution values of given input.
54
+
55
+ """
56
+ U, V = split_matrix(X)
57
+ return U * V
58
+
59
+ def partial_derivative(self, X):
60
+ """Compute the conditional probability of one event conditiones to the other.
61
+
62
+ In the case of the independence copula, due to C(u,v) = u*v, we have that
63
+ F(u|v) = dC/du = v.
64
+
65
+ Args:
66
+ X()
67
+
68
+ """
69
+ _, V = split_matrix(X)
70
+ return V
71
+
72
+ def percent_point(self, y, V):
73
+ """Compute the inverse of conditional cumulative distribution :math:`F(u|v)^-1`.
74
+
75
+ Args:
76
+ y: `np.ndarray` value of :math:`F(u|v)`.
77
+ v: `np.ndarray` given value of v.
78
+
79
+ """
80
+ self.check_fit()
81
+ return y
@@ -0,0 +1,19 @@
1
+ """Utilities for bivariate copulas."""
2
+
3
+ import numpy as np
4
+
5
+
6
+ def split_matrix(X):
7
+ """Split an (n,2) numpy.array into two vectors.
8
+
9
+ Args:
10
+ X(numpy.array): Matrix of shape (n,2)
11
+
12
+ Returns:
13
+ tuple[numpy.array]: Both of shape (n,)
14
+
15
+ """
16
+ if len(X):
17
+ return X[:, 0], X[:, 1]
18
+
19
+ return np.array([]), np.array([])