skfolio 0.7.0__py3-none-any.whl → 0.8.1__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.
- skfolio/__init__.py +2 -2
- skfolio/cluster/__init__.py +1 -1
- skfolio/cluster/_hierarchical.py +1 -1
- skfolio/datasets/__init__.py +1 -1
- skfolio/datasets/_base.py +2 -2
- skfolio/datasets/data/__init__.py +1 -0
- skfolio/distance/__init__.py +1 -1
- skfolio/distance/_base.py +2 -2
- skfolio/distance/_distance.py +4 -4
- skfolio/distribution/__init__.py +56 -0
- skfolio/distribution/_base.py +203 -0
- skfolio/distribution/copula/__init__.py +35 -0
- skfolio/distribution/copula/_base.py +456 -0
- skfolio/distribution/copula/_clayton.py +539 -0
- skfolio/distribution/copula/_gaussian.py +407 -0
- skfolio/distribution/copula/_gumbel.py +560 -0
- skfolio/distribution/copula/_independent.py +196 -0
- skfolio/distribution/copula/_joe.py +609 -0
- skfolio/distribution/copula/_selection.py +111 -0
- skfolio/distribution/copula/_student_t.py +486 -0
- skfolio/distribution/copula/_utils.py +509 -0
- skfolio/distribution/multivariate/__init__.py +11 -0
- skfolio/distribution/multivariate/_base.py +241 -0
- skfolio/distribution/multivariate/_utils.py +632 -0
- skfolio/distribution/multivariate/_vine_copula.py +1254 -0
- skfolio/distribution/univariate/__init__.py +19 -0
- skfolio/distribution/univariate/_base.py +308 -0
- skfolio/distribution/univariate/_gaussian.py +136 -0
- skfolio/distribution/univariate/_johnson_su.py +152 -0
- skfolio/distribution/univariate/_normal_inverse_gaussian.py +153 -0
- skfolio/distribution/univariate/_selection.py +85 -0
- skfolio/distribution/univariate/_student_t.py +144 -0
- skfolio/exceptions.py +6 -6
- skfolio/measures/__init__.py +1 -1
- skfolio/measures/_enums.py +7 -7
- skfolio/measures/_measures.py +4 -7
- skfolio/metrics/__init__.py +2 -0
- skfolio/metrics/_scorer.py +4 -4
- skfolio/model_selection/__init__.py +2 -2
- skfolio/model_selection/_combinatorial.py +15 -12
- skfolio/model_selection/_validation.py +2 -2
- skfolio/model_selection/_walk_forward.py +3 -3
- skfolio/moments/covariance/_base.py +1 -1
- skfolio/moments/covariance/_denoise_covariance.py +1 -1
- skfolio/moments/covariance/_detone_covariance.py +1 -1
- skfolio/moments/covariance/_empirical_covariance.py +1 -1
- skfolio/moments/covariance/_ew_covariance.py +1 -1
- skfolio/moments/covariance/_gerber_covariance.py +1 -1
- skfolio/moments/covariance/_graphical_lasso_cv.py +1 -1
- skfolio/moments/covariance/_implied_covariance.py +2 -7
- skfolio/moments/covariance/_ledoit_wolf.py +1 -1
- skfolio/moments/covariance/_oas.py +1 -1
- skfolio/moments/covariance/_shrunk_covariance.py +1 -1
- skfolio/moments/expected_returns/_base.py +1 -1
- skfolio/moments/expected_returns/_empirical_mu.py +1 -1
- skfolio/moments/expected_returns/_equilibrium_mu.py +1 -1
- skfolio/moments/expected_returns/_ew_mu.py +1 -1
- skfolio/moments/expected_returns/_shrunk_mu.py +2 -2
- skfolio/optimization/__init__.py +2 -0
- skfolio/optimization/_base.py +2 -2
- skfolio/optimization/cluster/__init__.py +2 -0
- skfolio/optimization/cluster/_nco.py +7 -7
- skfolio/optimization/cluster/hierarchical/__init__.py +2 -0
- skfolio/optimization/cluster/hierarchical/_base.py +1 -2
- skfolio/optimization/cluster/hierarchical/_herc.py +2 -2
- skfolio/optimization/cluster/hierarchical/_hrp.py +2 -2
- skfolio/optimization/convex/__init__.py +2 -0
- skfolio/optimization/convex/_base.py +8 -8
- skfolio/optimization/convex/_distributionally_robust.py +4 -4
- skfolio/optimization/convex/_maximum_diversification.py +5 -5
- skfolio/optimization/convex/_mean_risk.py +5 -6
- skfolio/optimization/convex/_risk_budgeting.py +3 -3
- skfolio/optimization/ensemble/__init__.py +2 -0
- skfolio/optimization/ensemble/_base.py +2 -2
- skfolio/optimization/ensemble/_stacking.py +1 -1
- skfolio/optimization/naive/__init__.py +2 -0
- skfolio/optimization/naive/_naive.py +1 -1
- skfolio/population/__init__.py +2 -0
- skfolio/population/_population.py +35 -9
- skfolio/portfolio/_base.py +42 -8
- skfolio/portfolio/_multi_period_portfolio.py +3 -2
- skfolio/portfolio/_portfolio.py +4 -4
- skfolio/pre_selection/__init__.py +2 -0
- skfolio/pre_selection/_drop_correlated.py +2 -2
- skfolio/pre_selection/_select_complete.py +25 -26
- skfolio/pre_selection/_select_k_extremes.py +2 -2
- skfolio/pre_selection/_select_non_dominated.py +2 -2
- skfolio/pre_selection/_select_non_expiring.py +2 -2
- skfolio/preprocessing/__init__.py +2 -0
- skfolio/preprocessing/_returns.py +2 -2
- skfolio/prior/__init__.py +4 -0
- skfolio/prior/_base.py +2 -2
- skfolio/prior/_black_litterman.py +5 -3
- skfolio/prior/_empirical.py +3 -1
- skfolio/prior/_factor_model.py +8 -4
- skfolio/prior/_synthetic_data.py +239 -0
- skfolio/synthetic_returns/__init__.py +1 -0
- skfolio/typing.py +1 -1
- skfolio/uncertainty_set/__init__.py +2 -0
- skfolio/uncertainty_set/_base.py +2 -2
- skfolio/uncertainty_set/_bootstrap.py +1 -1
- skfolio/uncertainty_set/_empirical.py +1 -1
- skfolio/utils/__init__.py +1 -0
- skfolio/utils/bootstrap.py +2 -2
- skfolio/utils/equations.py +13 -10
- skfolio/utils/sorting.py +2 -2
- skfolio/utils/stats.py +7 -7
- skfolio/utils/tools.py +76 -12
- {skfolio-0.7.0.dist-info → skfolio-0.8.1.dist-info}/METADATA +99 -24
- skfolio-0.8.1.dist-info/RECORD +120 -0
- {skfolio-0.7.0.dist-info → skfolio-0.8.1.dist-info}/WHEEL +1 -1
- skfolio-0.7.0.dist-info/RECORD +0 -95
- {skfolio-0.7.0.dist-info → skfolio-0.8.1.dist-info/licenses}/LICENSE +0 -0
- {skfolio-0.7.0.dist-info → skfolio-0.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,196 @@
|
|
1
|
+
"""Bivariate Independent Copula Estimation."""
|
2
|
+
|
3
|
+
# Copyright (c) 2025
|
4
|
+
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
5
|
+
# Credits: Matteo Manzi, Vincent Maladière, Carlo Nicolini
|
6
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
7
|
+
|
8
|
+
import numpy as np
|
9
|
+
import numpy.typing as npt
|
10
|
+
import sklearn.utils.validation as skv
|
11
|
+
|
12
|
+
from skfolio.distribution.copula._base import BaseBivariateCopula
|
13
|
+
|
14
|
+
|
15
|
+
class IndependentCopula(BaseBivariateCopula):
|
16
|
+
r"""Bivariate Independent Copula (also called the product copula).
|
17
|
+
|
18
|
+
It is defined by:
|
19
|
+
|
20
|
+
.. math::
|
21
|
+
C(u, v) = u \cdot v
|
22
|
+
|
23
|
+
Parameters
|
24
|
+
----------
|
25
|
+
random_state : int, RandomState instance or None, default=None
|
26
|
+
Seed or random state to ensure reproducibility.
|
27
|
+
|
28
|
+
References
|
29
|
+
----------
|
30
|
+
.. [1] "An Introduction to Copulas (2nd ed.)",
|
31
|
+
Nelsen (2006)
|
32
|
+
|
33
|
+
.. [2] "Multivariate Models and Dependence Concepts",
|
34
|
+
Joe, Chapman & Hall (1997)
|
35
|
+
|
36
|
+
.. [3] "Quantitative Risk Management: Concepts, Techniques and Tools",
|
37
|
+
McNeil, Frey & Embrechts (2005)
|
38
|
+
|
39
|
+
.. [4] "The t Copula and Related Copulas",
|
40
|
+
Demarta & McNeil (2005)
|
41
|
+
|
42
|
+
.. [5] "Copula Methods in Finance",
|
43
|
+
Cherubini, Luciano & Vecchiato (2004)
|
44
|
+
"""
|
45
|
+
|
46
|
+
_n_params = 0
|
47
|
+
|
48
|
+
def __init__(self, random_state: int | None = None):
|
49
|
+
super().__init__(random_state=random_state)
|
50
|
+
|
51
|
+
def fit(self, X: npt.ArrayLike, y=None) -> "IndependentCopula":
|
52
|
+
"""Fit the Bivariate Independent Copula.
|
53
|
+
|
54
|
+
Provided for compatibility with the API.
|
55
|
+
|
56
|
+
Parameters
|
57
|
+
----------
|
58
|
+
X : array-like of shape (n_observations, 2)
|
59
|
+
An array of bivariate inputs `(u, v)` where each row represents a
|
60
|
+
bivariate observation. Both `u` and `v` must be in the interval [0, 1],
|
61
|
+
having been transformed to uniform marginals.
|
62
|
+
|
63
|
+
y : None
|
64
|
+
Ignored. Provided for compatibility with scikit-learn's API.
|
65
|
+
|
66
|
+
Returns
|
67
|
+
-------
|
68
|
+
self : IndependentCopula
|
69
|
+
Returns the instance itself.
|
70
|
+
"""
|
71
|
+
_ = self._validate_X(X, reset=True)
|
72
|
+
return self
|
73
|
+
|
74
|
+
def cdf(self, X: npt.ArrayLike) -> np.ndarray:
|
75
|
+
"""Compute the CDF of the bivariate Independent copula.
|
76
|
+
|
77
|
+
Parameters
|
78
|
+
----------
|
79
|
+
X : array-like of shape (n_observations, 2)
|
80
|
+
An array of bivariate inputs `(u, v)` where each row represents a
|
81
|
+
bivariate observation. Both `u` and `v` must be in the interval `[0, 1]`,
|
82
|
+
having been transformed to uniform marginals.
|
83
|
+
|
84
|
+
Returns
|
85
|
+
-------
|
86
|
+
cdf : ndarray of shape (n_observations,)
|
87
|
+
CDF values for each observation in X.
|
88
|
+
"""
|
89
|
+
skv.check_is_fitted(self)
|
90
|
+
X = self._validate_X(X, reset=False)
|
91
|
+
cdf = X.prod(axis=1)
|
92
|
+
return cdf
|
93
|
+
|
94
|
+
def partial_derivative(
|
95
|
+
self, X: npt.ArrayLike, first_margin: bool = False
|
96
|
+
) -> np.ndarray:
|
97
|
+
r"""Compute the h-function (partial derivative) for the bivariate Independent
|
98
|
+
copula.
|
99
|
+
|
100
|
+
The h-function with respect to the second margin represents the conditional
|
101
|
+
distribution function of :math:`u` given :math:`v`:
|
102
|
+
|
103
|
+
.. math::
|
104
|
+
\frac{\partial C(u,v)}{\partial v}=u,
|
105
|
+
|
106
|
+
Parameters
|
107
|
+
----------
|
108
|
+
X : array-like of shape (n_samples, 2)
|
109
|
+
Array of pairs :math:`(u,v)`, where each value is in the interval [0,1].
|
110
|
+
|
111
|
+
Returns
|
112
|
+
-------
|
113
|
+
np.ndarray
|
114
|
+
Array of h-function values for each observation in X.
|
115
|
+
"""
|
116
|
+
skv.check_is_fitted(self)
|
117
|
+
X = self._validate_X(X, reset=False)
|
118
|
+
h = X[:, 1] if first_margin else X[:, 0]
|
119
|
+
return h
|
120
|
+
|
121
|
+
def inverse_partial_derivative(
|
122
|
+
self, X: npt.ArrayLike, first_margin: bool = False
|
123
|
+
) -> np.ndarray:
|
124
|
+
r"""Compute the inverse of the bivariate copula's partial derivative, commonly
|
125
|
+
known as the inverse h-function.
|
126
|
+
|
127
|
+
For the independent copula, the h-function with respect to the second margin is
|
128
|
+
|
129
|
+
.. math::
|
130
|
+
h(u\mid v)= u,
|
131
|
+
|
132
|
+
and the derivative with respect to the first margin is
|
133
|
+
|
134
|
+
.. math::
|
135
|
+
g(u,v)= v.
|
136
|
+
|
137
|
+
Their inverses are trivial:
|
138
|
+
|
139
|
+
- Given (p,v) for h(u|v)= p, we have u = p.
|
140
|
+
- Given (p,u) for g(u,v)= p, we have v = p.
|
141
|
+
|
142
|
+
Parameters
|
143
|
+
----------
|
144
|
+
X : array-like of shape (n_observations, 2)
|
145
|
+
An array of bivariate inputs `(p, v)`, each in the interval `[0, 1]`.
|
146
|
+
- The first column `p` corresponds to the value of the h-function.
|
147
|
+
- The second column `v` is the conditioning variable.
|
148
|
+
|
149
|
+
first_margin : bool, default=False
|
150
|
+
If True, compute the inverse partial derivative with respect to the first
|
151
|
+
margin `u`; otherwise, compute the inverse partial derivative with respect
|
152
|
+
to the second margin `v`.
|
153
|
+
|
154
|
+
Returns
|
155
|
+
-------
|
156
|
+
u : ndarray of shape (n_observations,)
|
157
|
+
A 1D-array of length `n_observations`, where each element is the computed
|
158
|
+
:math:`u = h^{-1}(p \mid v)` for the corresponding pair in `X`.
|
159
|
+
"""
|
160
|
+
skv.check_is_fitted(self)
|
161
|
+
X = self._validate_X(X, reset=False)
|
162
|
+
u = X[:, 1] if first_margin else X[:, 0]
|
163
|
+
return u
|
164
|
+
|
165
|
+
def score_samples(self, X: npt.ArrayLike) -> np.ndarray:
|
166
|
+
"""Compute the log-likelihood of each sample (log-pdf) under the model.
|
167
|
+
|
168
|
+
Parameters
|
169
|
+
----------
|
170
|
+
X : array-like of shape (n_samples, 2)
|
171
|
+
The input data where each row represents a bivariate observation.
|
172
|
+
The data should be transformed to uniform marginals in [0, 1].
|
173
|
+
|
174
|
+
Returns
|
175
|
+
-------
|
176
|
+
density : ndarray of shape (n_samples,)
|
177
|
+
The log-likelihood of each sample under the fitted copula.
|
178
|
+
"""
|
179
|
+
skv.check_is_fitted(self)
|
180
|
+
X = self._validate_X(X, reset=False)
|
181
|
+
return np.zeros(X.shape[0]) # log(1.0)
|
182
|
+
|
183
|
+
@property
|
184
|
+
def lower_tail_dependence(self) -> float:
|
185
|
+
"""Theoretical lower tail dependence coefficient."""
|
186
|
+
return 0
|
187
|
+
|
188
|
+
@property
|
189
|
+
def upper_tail_dependence(self) -> float:
|
190
|
+
"""Theoretical upper tail dependence coefficient."""
|
191
|
+
return 0
|
192
|
+
|
193
|
+
@property
|
194
|
+
def fitted_repr(self) -> str:
|
195
|
+
"""String representation of the fitted copula."""
|
196
|
+
return f"{self.__class__.__name__}()"
|