skfolio 0.6.0__py3-none-any.whl → 0.7.0__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.
Files changed (61) hide show
  1. skfolio/__init__.py +5 -5
  2. skfolio/cluster/__init__.py +1 -1
  3. skfolio/cluster/_hierarchical.py +1 -1
  4. skfolio/datasets/__init__.py +2 -2
  5. skfolio/distance/__init__.py +3 -3
  6. skfolio/distance/_distance.py +7 -6
  7. skfolio/exceptions.py +2 -2
  8. skfolio/measures/__init__.py +23 -23
  9. skfolio/model_selection/__init__.py +2 -2
  10. skfolio/moments/__init__.py +11 -11
  11. skfolio/moments/covariance/__init__.py +6 -6
  12. skfolio/moments/covariance/_denoise_covariance.py +2 -1
  13. skfolio/moments/covariance/_detone_covariance.py +2 -1
  14. skfolio/moments/covariance/_empirical_covariance.py +2 -1
  15. skfolio/moments/covariance/_ew_covariance.py +2 -1
  16. skfolio/moments/covariance/_gerber_covariance.py +2 -1
  17. skfolio/moments/covariance/_implied_covariance.py +1 -1
  18. skfolio/moments/expected_returns/__init__.py +2 -2
  19. skfolio/moments/expected_returns/_empirical_mu.py +2 -1
  20. skfolio/moments/expected_returns/_equilibrium_mu.py +2 -1
  21. skfolio/moments/expected_returns/_ew_mu.py +2 -1
  22. skfolio/moments/expected_returns/_shrunk_mu.py +2 -1
  23. skfolio/optimization/__init__.py +10 -10
  24. skfolio/optimization/cluster/__init__.py +1 -1
  25. skfolio/optimization/cluster/_nco.py +3 -2
  26. skfolio/optimization/cluster/hierarchical/__init__.py +1 -1
  27. skfolio/optimization/cluster/hierarchical/_herc.py +2 -1
  28. skfolio/optimization/cluster/hierarchical/_hrp.py +2 -1
  29. skfolio/optimization/convex/__init__.py +3 -3
  30. skfolio/optimization/convex/_base.py +2 -1
  31. skfolio/optimization/convex/_distributionally_robust.py +4 -1
  32. skfolio/optimization/convex/_maximum_diversification.py +3 -1
  33. skfolio/optimization/convex/_mean_risk.py +5 -2
  34. skfolio/optimization/convex/_risk_budgeting.py +3 -1
  35. skfolio/optimization/ensemble/_stacking.py +2 -2
  36. skfolio/optimization/naive/__init__.py +1 -1
  37. skfolio/optimization/naive/_naive.py +3 -2
  38. skfolio/portfolio/__init__.py +1 -1
  39. skfolio/portfolio/_base.py +1 -0
  40. skfolio/portfolio/_portfolio.py +1 -0
  41. skfolio/pre_selection/__init__.py +1 -1
  42. skfolio/pre_selection/_drop_correlated.py +1 -1
  43. skfolio/pre_selection/_select_complete.py +6 -4
  44. skfolio/pre_selection/_select_k_extremes.py +1 -1
  45. skfolio/pre_selection/_select_non_dominated.py +1 -1
  46. skfolio/pre_selection/_select_non_expiring.py +6 -4
  47. skfolio/prior/__init__.py +3 -3
  48. skfolio/prior/_black_litterman.py +2 -1
  49. skfolio/prior/_empirical.py +2 -1
  50. skfolio/prior/_factor_model.py +2 -1
  51. skfolio/typing.py +6 -6
  52. skfolio/uncertainty_set/__init__.py +5 -5
  53. skfolio/uncertainty_set/_base.py +3 -2
  54. skfolio/utils/stats.py +8 -8
  55. skfolio/utils/tools.py +10 -10
  56. {skfolio-0.6.0.dist-info → skfolio-0.7.0.dist-info}/METADATA +32 -31
  57. skfolio-0.7.0.dist-info/RECORD +95 -0
  58. {skfolio-0.6.0.dist-info → skfolio-0.7.0.dist-info}/WHEEL +1 -1
  59. skfolio-0.6.0.dist-info/RECORD +0 -95
  60. {skfolio-0.6.0.dist-info → skfolio-0.7.0.dist-info}/LICENSE +0 -0
  61. {skfolio-0.6.0.dist-info → skfolio-0.7.0.dist-info}/top_level.txt +0 -0
skfolio/__init__.py CHANGED
@@ -18,12 +18,12 @@ __version__ = importlib.metadata.version("skfolio")
18
18
 
19
19
  __all__ = [
20
20
  "BaseMeasure",
21
- "PerfMeasure",
22
- "RiskMeasure",
23
- "ExtraRiskMeasure",
24
- "RatioMeasure",
25
21
  "BasePortfolio",
26
- "Portfolio",
22
+ "ExtraRiskMeasure",
27
23
  "MultiPeriodPortfolio",
24
+ "PerfMeasure",
28
25
  "Population",
26
+ "Portfolio",
27
+ "RatioMeasure",
28
+ "RiskMeasure",
29
29
  ]
@@ -5,4 +5,4 @@
5
5
 
6
6
  from skfolio.cluster._hierarchical import HierarchicalClustering, LinkageMethod
7
7
 
8
- __all__ = ["LinkageMethod", "HierarchicalClustering"]
8
+ __all__ = ["HierarchicalClustering", "LinkageMethod"]
@@ -180,7 +180,7 @@ class HierarchicalClustering(skb.ClusterMixin, skb.BaseEstimator):
180
180
  self : HierarchicalClustering
181
181
  Fitted estimator.
182
182
  """
183
- X = self._validate_data(X)
183
+ X = skv.validate_data(self, X)
184
184
  assert_is_distance(X)
185
185
  self.condensed_distance_ = scd.squareform(X, checks=False)
186
186
  self.linkage_matrix_ = sch.linkage(
@@ -13,10 +13,10 @@ from skfolio.datasets._base import (
13
13
  )
14
14
 
15
15
  __all__ = [
16
- "load_nasdaq_dataset",
17
16
  "load_factors_dataset",
18
17
  "load_ftse100_dataset",
18
+ "load_nasdaq_dataset",
19
19
  "load_sp500_dataset",
20
- "load_sp500_index",
21
20
  "load_sp500_implied_vol_dataset",
21
+ "load_sp500_index",
22
22
  ]
@@ -16,11 +16,11 @@ from skfolio.distance._distance import (
16
16
 
17
17
  __all__ = [
18
18
  "BaseDistance",
19
- "PearsonDistance",
20
- "KendallDistance",
21
- "SpearmanDistance",
22
19
  "CovarianceDistance",
23
20
  "DistanceCorrelation",
21
+ "KendallDistance",
24
22
  "MutualInformation",
25
23
  "NBinsMethod",
24
+ "PearsonDistance",
25
+ "SpearmanDistance",
26
26
  ]
@@ -11,6 +11,7 @@ import scipy.spatial.distance as scd
11
11
  import scipy.stats as sct
12
12
  import sklearn.metrics as skmc
13
13
  import sklearn.utils.metadata_routing as skm
14
+ import sklearn.utils.validation as skv
14
15
 
15
16
  from skfolio.distance._base import BaseDistance
16
17
  from skfolio.moments import BaseCovariance, GerberCovariance
@@ -85,7 +86,7 @@ class PearsonDistance(BaseDistance):
85
86
  self : PearsonDistance
86
87
  Fitted estimator.
87
88
  """
88
- X = self._validate_data(X)
89
+ X = skv.validate_data(self, X)
89
90
  corr = np.corrcoef(X.T)
90
91
  self.codependence_, self.distance_ = _corr_to_distance(
91
92
  corr, absolute=self.absolute, power=self.power
@@ -157,7 +158,7 @@ class KendallDistance(BaseDistance):
157
158
  self : KendallDistance
158
159
  Fitted estimator.
159
160
  """
160
- X = self._validate_data(X)
161
+ X = skv.validate_data(self, X)
161
162
  corr = pd.DataFrame(X).corr(method="kendall").to_numpy()
162
163
  self.codependence_, self.distance_ = _corr_to_distance(
163
164
  corr, absolute=self.absolute, power=self.power
@@ -229,7 +230,7 @@ class SpearmanDistance(BaseDistance):
229
230
  self : SpearmanDistance
230
231
  Fitted estimator.
231
232
  """
232
- X = self._validate_data(X)
233
+ X = skv.validate_data(self, X)
233
234
  corr = pd.DataFrame(X).corr(method="spearman").to_numpy()
234
235
  self.codependence_, self.distance_ = _corr_to_distance(
235
236
  corr, absolute=self.absolute, power=self.power
@@ -337,7 +338,7 @@ class CovarianceDistance(BaseDistance):
337
338
 
338
339
  # we validate and convert to numpy after all models have been fitted to keep the
339
340
  # features names information.
340
- _ = self._validate_data(X)
341
+ _ = skv.validate_data(self, X)
341
342
 
342
343
  corr, _ = cov_to_corr(self.covariance_estimator_.covariance_)
343
344
  self.codependence_, self.distance_ = _corr_to_distance(
@@ -409,7 +410,7 @@ class DistanceCorrelation(BaseDistance):
409
410
  self : DistanceCorrelation
410
411
  Fitted estimator.
411
412
  """
412
- X = self._validate_data(X)
413
+ X = skv.validate_data(self, X)
413
414
  n_assets = X.shape[1]
414
415
  corr = np.ones((n_assets, n_assets))
415
416
  # TODO: parallelize
@@ -502,7 +503,7 @@ class MutualInformation(BaseDistance):
502
503
  self : MutualInformation
503
504
  Fitted estimator.
504
505
  """
505
- X = self._validate_data(X)
506
+ X = skv.validate_data(self, X)
506
507
  n_assets = X.shape[1]
507
508
  if self.n_bins is None:
508
509
  match self.n_bins_method:
skfolio/exceptions.py CHANGED
@@ -8,11 +8,11 @@ classes used across skfolio.
8
8
  # License: BSD 3 clause
9
9
 
10
10
  __all__ = [
11
- "OptimizationError",
11
+ "DuplicateGroupsError",
12
12
  "EquationToMatrixError",
13
13
  "GroupNotFoundError",
14
14
  "NonPositiveVarianceError",
15
- "DuplicateGroupsError",
15
+ "OptimizationError",
16
16
  ]
17
17
 
18
18
 
@@ -43,36 +43,36 @@ from skfolio.measures._measures import (
43
43
 
44
44
  __all__ = [
45
45
  "BaseMeasure",
46
- "PerfMeasure",
47
- "RiskMeasure",
48
46
  "ExtraRiskMeasure",
47
+ "PerfMeasure",
49
48
  "RatioMeasure",
50
- "mean",
49
+ "RiskMeasure",
50
+ "average_drawdown",
51
+ "cdar",
52
+ "cvar",
53
+ "drawdown_at_risk",
54
+ "edar",
55
+ "effective_number_assets",
56
+ "entropic_risk_measure",
57
+ "evar",
58
+ "first_lower_partial_moment",
59
+ "fourth_central_moment",
60
+ "fourth_lower_partial_moment",
51
61
  "get_cumulative_returns",
52
62
  "get_drawdowns",
53
- "variance",
63
+ "gini_mean_difference",
64
+ "kurtosis",
65
+ "max_drawdown",
66
+ "mean",
67
+ "mean_absolute_deviation",
68
+ "owa_gmd_weights",
69
+ "semi_deviation",
54
70
  "semi_variance",
71
+ "skew",
55
72
  "standard_deviation",
56
- "semi_deviation",
57
73
  "third_central_moment",
58
- "fourth_central_moment",
59
- "fourth_lower_partial_moment",
60
- "cvar",
61
- "mean_absolute_deviation",
74
+ "ulcer_index",
62
75
  "value_at_risk",
76
+ "variance",
63
77
  "worst_realization",
64
- "first_lower_partial_moment",
65
- "entropic_risk_measure",
66
- "evar",
67
- "drawdown_at_risk",
68
- "cdar",
69
- "max_drawdown",
70
- "average_drawdown",
71
- "edar",
72
- "ulcer_index",
73
- "gini_mean_difference",
74
- "owa_gmd_weights",
75
- "skew",
76
- "kurtosis",
77
- "effective_number_assets",
78
78
  ]
@@ -12,9 +12,9 @@ from skfolio.model_selection._validation import cross_val_predict
12
12
  from skfolio.model_selection._walk_forward import WalkForward
13
13
 
14
14
  __all__ = [
15
- "cross_val_predict",
16
- "WalkForward",
17
15
  "BaseCombinatorialCV",
18
16
  "CombinatorialPurgedCV",
17
+ "WalkForward",
18
+ "cross_val_predict",
19
19
  "optimal_folds_number",
20
20
  ]
@@ -23,21 +23,21 @@ from skfolio.moments.expected_returns import (
23
23
  )
24
24
 
25
25
  __all__ = [
26
+ "OAS",
27
+ "BaseCovariance",
26
28
  "BaseMu",
27
- "EmpiricalMu",
29
+ "DenoiseCovariance",
30
+ "DetoneCovariance",
31
+ "EWCovariance",
28
32
  "EWMu",
29
- "ShrunkMu",
30
- "EquilibriumMu",
31
- "ShrunkMuMethods",
32
- "BaseCovariance",
33
33
  "EmpiricalCovariance",
34
- "EWCovariance",
34
+ "EmpiricalMu",
35
+ "EquilibriumMu",
35
36
  "GerberCovariance",
36
- "DenoiseCovariance",
37
- "DetoneCovariance",
38
- "LedoitWolf",
39
- "OAS",
40
- "ShrunkCovariance",
41
37
  "GraphicalLassoCV",
42
38
  "ImpliedCovariance",
39
+ "LedoitWolf",
40
+ "ShrunkCovariance",
41
+ "ShrunkMu",
42
+ "ShrunkMuMethods",
43
43
  ]
@@ -15,15 +15,15 @@ from skfolio.moments.covariance._oas import OAS
15
15
  from skfolio.moments.covariance._shrunk_covariance import ShrunkCovariance
16
16
 
17
17
  __all__ = [
18
+ "OAS",
18
19
  "BaseCovariance",
19
- "EmpiricalCovariance",
20
- "EWCovariance",
21
- "GerberCovariance",
22
20
  "DenoiseCovariance",
23
21
  "DetoneCovariance",
24
- "LedoitWolf",
25
- "OAS",
26
- "ShrunkCovariance",
22
+ "EWCovariance",
23
+ "EmpiricalCovariance",
24
+ "GerberCovariance",
27
25
  "GraphicalLassoCV",
28
26
  "ImpliedCovariance",
27
+ "LedoitWolf",
28
+ "ShrunkCovariance",
29
29
  ]
@@ -12,6 +12,7 @@ import numpy.typing as npt
12
12
  import scipy.optimize as sco
13
13
  import sklearn.neighbors as skn
14
14
  import sklearn.utils.metadata_routing as skm
15
+ import sklearn.utils.validation as skv
15
16
 
16
17
  from skfolio.moments.covariance._base import BaseCovariance
17
18
  from skfolio.moments.covariance._empirical_covariance import EmpiricalCovariance
@@ -139,7 +140,7 @@ class DenoiseCovariance(BaseCovariance):
139
140
 
140
141
  # we validate and convert to numpy after all models have been fitted to keep
141
142
  # features names information.
142
- X = self._validate_data(X)
143
+ X = skv.validate_data(self, X)
143
144
  n_observations, n_assets = X.shape
144
145
  q = n_observations / n_assets
145
146
  corr, std = cov_to_corr(self.covariance_estimator_.covariance_)
@@ -10,6 +10,7 @@
10
10
  import numpy as np
11
11
  import numpy.typing as npt
12
12
  import sklearn.utils.metadata_routing as skm
13
+ import sklearn.utils.validation as skv
13
14
 
14
15
  from skfolio.moments.covariance._base import BaseCovariance
15
16
  from skfolio.moments.covariance._empirical_covariance import EmpiricalCovariance
@@ -141,7 +142,7 @@ class DetoneCovariance(BaseCovariance):
141
142
 
142
143
  # we validate and convert to numpy after all models have been fitted to keep
143
144
  # features names information.
144
- _ = self._validate_data(X)
145
+ _ = skv.validate_data(self, X)
145
146
  corr, std = cov_to_corr(self.covariance_estimator_.covariance_)
146
147
  e_val, e_vec = np.linalg.eigh(corr)
147
148
  indices = e_val.argsort()[::-1]
@@ -9,6 +9,7 @@
9
9
 
10
10
  import numpy as np
11
11
  import numpy.typing as npt
12
+ import sklearn.utils.validation as skv
12
13
 
13
14
  from skfolio.moments.covariance._base import BaseCovariance
14
15
 
@@ -92,7 +93,7 @@ class EmpiricalCovariance(BaseCovariance):
92
93
  self : EmpiricalCovariance
93
94
  Fitted estimator.
94
95
  """
95
- X = self._validate_data(X)
96
+ X = skv.validate_data(self, X)
96
97
  if self.window_size is not None:
97
98
  X = X[-int(self.window_size) :]
98
99
  covariance = np.cov(X.T, ddof=self.ddof)
@@ -9,6 +9,7 @@
9
9
 
10
10
  import numpy.typing as npt
11
11
  import pandas as pd
12
+ import sklearn.utils.validation as skv
12
13
 
13
14
  from skfolio.moments.covariance._base import BaseCovariance
14
15
 
@@ -94,7 +95,7 @@ class EWCovariance(BaseCovariance):
94
95
  self : EWCovariance
95
96
  Fitted estimator.
96
97
  """
97
- X = self._validate_data(X)
98
+ X = skv.validate_data(self, X)
98
99
  if self.window_size is not None:
99
100
  X = X[-int(self.window_size) :]
100
101
  n_observations = X.shape[0]
@@ -9,6 +9,7 @@
9
9
 
10
10
  import numpy as np
11
11
  import numpy.typing as npt
12
+ import sklearn.utils.validation as skv
12
13
 
13
14
  from skfolio.moments.covariance._base import BaseCovariance
14
15
  from skfolio.utils.stats import corr_to_cov
@@ -131,7 +132,7 @@ class GerberCovariance(BaseCovariance):
131
132
  self : GerberCovariance
132
133
  Fitted estimator.
133
134
  """
134
- X = self._validate_data(X)
135
+ X = skv.validate_data(self, X)
135
136
  if self.window_size is not None:
136
137
  X = X[-self.window_size :]
137
138
  if not (1 > self.threshold > 0):
@@ -272,7 +272,7 @@ class ImpliedCovariance(BaseCovariance):
272
272
  # and re-order to follow returns ordering.
273
273
  implied_vol = safe_indexing(implied_vol, indices=indices, axis=1)
274
274
 
275
- X = self._validate_data(X)
275
+ X = skv.validate_data(self, X)
276
276
  _, n_assets = X.shape
277
277
  implied_vol = check_implied_vol(implied_vol=implied_vol, X=X)
278
278
  implied_vol /= np.sqrt(self.annualized_factor)
@@ -10,9 +10,9 @@ from skfolio.moments.expected_returns._shrunk_mu import ShrunkMu, ShrunkMuMethod
10
10
 
11
11
  __all__ = [
12
12
  "BaseMu",
13
- "EmpiricalMu",
14
13
  "EWMu",
15
- "ShrunkMu",
14
+ "EmpiricalMu",
16
15
  "EquilibriumMu",
16
+ "ShrunkMu",
17
17
  "ShrunkMuMethods",
18
18
  ]
@@ -9,6 +9,7 @@
9
9
 
10
10
  import numpy as np
11
11
  import numpy.typing as npt
12
+ import sklearn.utils.validation as skv
12
13
 
13
14
  from skfolio.moments.expected_returns._base import BaseMu
14
15
 
@@ -56,7 +57,7 @@ class EmpiricalMu(BaseMu):
56
57
  self : EmpiricalMu
57
58
  Fitted estimator.
58
59
  """
59
- X = self._validate_data(X)
60
+ X = skv.validate_data(self, X)
60
61
  if self.window_size is not None:
61
62
  X = X[-self.window_size :]
62
63
  self.mu_ = np.mean(X, axis=0)
@@ -10,6 +10,7 @@
10
10
  import numpy as np
11
11
  import numpy.typing as npt
12
12
  import sklearn.utils.metadata_routing as skm
13
+ import sklearn.utils.validation as skv
13
14
 
14
15
  from skfolio.moments.covariance import BaseCovariance, EmpiricalCovariance
15
16
  from skfolio.moments.expected_returns._base import BaseMu
@@ -114,7 +115,7 @@ class EquilibriumMu(BaseMu):
114
115
 
115
116
  # we validate and convert to numpy after all models have been fitted to keep
116
117
  # features names information.
117
- X = self._validate_data(X)
118
+ X = skv.validate_data(self, X)
118
119
  n_assets = X.shape[1]
119
120
  if self.weights is None:
120
121
  weights = np.ones(n_assets) / n_assets
@@ -9,6 +9,7 @@
9
9
 
10
10
  import numpy.typing as npt
11
11
  import pandas as pd
12
+ import sklearn.utils.validation as skv
12
13
 
13
14
  from skfolio.moments.expected_returns._base import BaseMu
14
15
 
@@ -62,7 +63,7 @@ class EWMu(BaseMu):
62
63
  self : EWMu
63
64
  Fitted estimator.
64
65
  """
65
- X = self._validate_data(X)
66
+ X = skv.validate_data(self, X)
66
67
  if self.window_size is not None:
67
68
  X = X[-self.window_size :]
68
69
  self.mu_ = pd.DataFrame(X).ewm(alpha=self.alpha).mean().iloc[-1, :].to_numpy()
@@ -13,6 +13,7 @@ from enum import auto
13
13
  import numpy as np
14
14
  import numpy.typing as npt
15
15
  import sklearn.utils.metadata_routing as skm
16
+ import sklearn.utils.validation as skv
16
17
 
17
18
  from skfolio.moments.covariance import BaseCovariance, EmpiricalCovariance
18
19
  from skfolio.moments.expected_returns._base import BaseMu
@@ -189,7 +190,7 @@ class ShrunkMu(BaseMu):
189
190
 
190
191
  # we validate and convert to numpy after all models have been fitted to keep
191
192
  # features names information.
192
- X = self._validate_data(X)
193
+ X = skv.validate_data(self, X)
193
194
  n_observations, n_assets = X.shape
194
195
 
195
196
  covariance = self.covariance_estimator_.covariance_
@@ -17,20 +17,20 @@ from skfolio.optimization.ensemble import BaseComposition, StackingOptimization
17
17
  from skfolio.optimization.naive import EqualWeighted, InverseVolatility, Random
18
18
 
19
19
  __all__ = [
20
+ "BaseComposition",
21
+ "BaseHierarchicalOptimization",
20
22
  "BaseOptimization",
21
- "InverseVolatility",
22
- "EqualWeighted",
23
- "Random",
24
- "ObjectiveFunction",
25
23
  "ConvexOptimization",
26
- "MeanRisk",
27
- "RiskBudgeting",
28
24
  "DistributionallyRobustCVaR",
29
- "MaximumDiversification",
30
- "BaseHierarchicalOptimization",
31
- "HierarchicalRiskParity",
25
+ "EqualWeighted",
32
26
  "HierarchicalEqualRiskContribution",
27
+ "HierarchicalRiskParity",
28
+ "InverseVolatility",
29
+ "MaximumDiversification",
30
+ "MeanRisk",
33
31
  "NestedClustersOptimization",
34
- "BaseComposition",
32
+ "ObjectiveFunction",
33
+ "Random",
34
+ "RiskBudgeting",
35
35
  "StackingOptimization",
36
36
  ]
@@ -7,7 +7,7 @@ from skfolio.optimization.cluster.hierarchical import (
7
7
 
8
8
  __all__ = [
9
9
  "BaseHierarchicalOptimization",
10
- "HierarchicalRiskParity",
11
10
  "HierarchicalEqualRiskContribution",
11
+ "HierarchicalRiskParity",
12
12
  "NestedClustersOptimization",
13
13
  ]
@@ -18,6 +18,7 @@ import sklearn.base as skb
18
18
  import sklearn.model_selection as sks
19
19
  import sklearn.utils.metadata_routing as skm
20
20
  import sklearn.utils.parallel as skp
21
+ import sklearn.utils.validation as skv
21
22
 
22
23
  import skfolio.typing as skt
23
24
  from skfolio.cluster import HierarchicalClustering
@@ -355,10 +356,10 @@ class NestedClustersOptimization(BaseOptimization):
355
356
  # We validate and convert to numpy array only after inner-estimator fitting to
356
357
  # keep the assets names in case they are used in the estimator.
357
358
  if y is not None:
358
- X, y = self._validate_data(X, y)
359
+ X, y = skv.validate_data(self, X, y)
359
360
  y_pred = y[test_indices]
360
361
  else:
361
- X = self._validate_data(X)
362
+ X = skv.validate_data(self, X)
362
363
  y_pred = None
363
364
 
364
365
  X_pred = []
@@ -8,6 +8,6 @@ from skfolio.optimization.cluster.hierarchical._hrp import HierarchicalRiskParit
8
8
 
9
9
  __all__ = [
10
10
  "BaseHierarchicalOptimization",
11
- "HierarchicalRiskParity",
12
11
  "HierarchicalEqualRiskContribution",
12
+ "HierarchicalRiskParity",
13
13
  ]
@@ -10,6 +10,7 @@ import numpy.typing as npt
10
10
  import pandas as pd
11
11
  import scipy.cluster.hierarchy as sch
12
12
  import sklearn.utils.metadata_routing as skm
13
+ import sklearn.utils.validation as skv
13
14
 
14
15
  import skfolio.typing as skt
15
16
  from skfolio.cluster import HierarchicalClustering
@@ -391,7 +392,7 @@ class HierarchicalEqualRiskContribution(BaseHierarchicalOptimization):
391
392
  labels = self.hierarchical_clustering_estimator_.labels_
392
393
  linkage_matrix = self.hierarchical_clustering_estimator_.linkage_matrix_
393
394
 
394
- X = self._validate_data(X)
395
+ X = skv.validate_data(self, X)
395
396
  n_assets = X.shape[1]
396
397
 
397
398
  min_weights, max_weights = self._convert_weights_bounds(n_assets=n_assets)
@@ -11,6 +11,7 @@ import numpy.typing as npt
11
11
  import pandas as pd
12
12
  import scipy.cluster.hierarchy as sch
13
13
  import sklearn.utils.metadata_routing as skm
14
+ import sklearn.utils.validation as skv
14
15
 
15
16
  import skfolio.typing as skt
16
17
  from skfolio.cluster import HierarchicalClustering
@@ -339,7 +340,7 @@ class HierarchicalRiskParity(BaseHierarchicalOptimization):
339
340
  X=distance, y=None, **routed_params.hierarchical_clustering_estimator.fit
340
341
  )
341
342
 
342
- X = self._validate_data(X)
343
+ X = skv.validate_data(self, X)
343
344
  n_assets = X.shape[1]
344
345
 
345
346
  min_weights, max_weights = self._convert_weights_bounds(n_assets=n_assets)
@@ -7,10 +7,10 @@ from skfolio.optimization.convex._mean_risk import MeanRisk
7
7
  from skfolio.optimization.convex._risk_budgeting import RiskBudgeting
8
8
 
9
9
  __all__ = [
10
- "ObjectiveFunction",
11
10
  "ConvexOptimization",
12
- "MeanRisk",
13
- "RiskBudgeting",
14
11
  "DistributionallyRobustCVaR",
15
12
  "MaximumDiversification",
13
+ "MeanRisk",
14
+ "ObjectiveFunction",
15
+ "RiskBudgeting",
16
16
  ]
@@ -1685,7 +1685,8 @@ class ConvexOptimization(BaseOptimization, ABC):
1685
1685
  z2 = cp.vstack([w_reshaped, factor_reshaped])
1686
1686
 
1687
1687
  risk = covariance_uncertainty_set.k * cp.pnorm(
1688
- sc.linalg.sqrtm(covariance_uncertainty_set.sigma) @ (cp.vec(x) + cp.vec(y)),
1688
+ sc.linalg.sqrtm(covariance_uncertainty_set.sigma)
1689
+ @ (cp.vec(x, order="F") + cp.vec(y, order="F")),
1689
1690
  2,
1690
1691
  ) + cp.trace(prior_model.covariance @ (x + y))
1691
1692
  # semi-definite positive constraints
@@ -8,6 +8,7 @@ import cvxpy as cp
8
8
  import numpy as np
9
9
  import numpy.typing as npt
10
10
  import sklearn.utils.metadata_routing as skm
11
+ import sklearn.utils.validation as skv
11
12
 
12
13
  import skfolio.typing as skt
13
14
  from skfolio.measures import RiskMeasure
@@ -331,7 +332,9 @@ class DistributionallyRobustCVaR(ConvexOptimization):
331
332
  """
332
333
  routed_params = skm.process_routing(self, "fit", **fit_params)
333
334
 
334
- self._check_feature_names(X, reset=True)
335
+ # `X` is unchanged and only `feature_names_in_` is performed
336
+ _ = skv.validate_data(self, X, skip_check_array=True)
337
+
335
338
  # Used to avoid adding multiple times similar constrains linked to identical
336
339
  # risk models
337
340
  self.prior_estimator_ = check_estimator(
@@ -6,6 +6,7 @@
6
6
 
7
7
  import numpy as np
8
8
  import numpy.typing as npt
9
+ import sklearn.utils.validation as skv
9
10
 
10
11
  import skfolio.typing as skt
11
12
  from skfolio.measures import RiskMeasure
@@ -423,7 +424,8 @@ class MaximumDiversification(MeanRisk):
423
424
  self : MaximumDiversification
424
425
  Fitted estimator.
425
426
  """
426
- self._check_feature_names(X, reset=True)
427
+ # `X` is unchanged and only `feature_names_in_` is performed
428
+ _ = skv.validate_data(self, X, skip_check_array=True)
427
429
 
428
430
  def func(w, obj):
429
431
  """weighted volatilities"""
@@ -13,6 +13,7 @@ import numpy.typing as npt
13
13
  import pandas as pd
14
14
  import sklearn as sk
15
15
  import sklearn.utils.metadata_routing as skm
16
+ import sklearn.utils.validation as skv
16
17
 
17
18
  import skfolio.typing as skt
18
19
  from skfolio.measures import RiskMeasure
@@ -764,7 +765,9 @@ class MeanRisk(ConvexOptimization):
764
765
  """
765
766
  routed_params = skm.process_routing(self, "fit", **fit_params)
766
767
 
767
- self._check_feature_names(X, reset=True)
768
+ # `X` is unchanged and only `feature_names_in_` is performed
769
+ _ = skv.validate_data(self, X, skip_check_array=True)
770
+
768
771
  # Validate
769
772
  self._validation()
770
773
  # Used to avoid adding multiple times similar constrains linked to identical
@@ -893,7 +896,7 @@ class MeanRisk(ConvexOptimization):
893
896
  " 1d-array, a single-column DataFrame or a Series"
894
897
  )
895
898
  y = y[y.columns[0]]
896
- _, y = self._validate_data(X, y)
899
+ _, y = skv.validate_data(self, X, y)
897
900
  tracking_error = self._tracking_error(
898
901
  prior_model=prior_model, w=w, y=y, factor=factor
899
902
  )