Skip to content

Commit 6ed1ded

Browse files
committed
deprecate min cov det #294
1 parent b20d510 commit 6ed1ded

File tree

3 files changed

+25
-28
lines changed

3 files changed

+25
-28
lines changed

docs/RiskModels.rst

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ covariance.
4444

4545
.. automodule:: pypfopt.risk_models
4646

47+
:exclude-members: min_cov_determinant
48+
4749
.. note::
4850

4951
For any of these methods, if you would prefer to pass returns (the default is prices),
@@ -94,13 +96,6 @@ covariance.
9496
`blog post <https://reasonabledeviations.com/2018/08/15/exponential-covariance/>`_
9597
on my academic website.
9698

97-
.. autofunction:: min_cov_determinant
98-
99-
The minimum covariance determinant (MCD) estimator is designed to be robust to
100-
outliers and 'contaminated' data [3]_. An efficient estimator is implemented in the
101-
:py:mod:`sklearn.covariance` module, which is based on the algorithm presented in
102-
Rousseeuw (1999) [4]_.
103-
10499
.. autofunction:: cov_to_corr
105100

106101
.. autofunction:: corr_to_cov

pypfopt/risk_models.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@ def fix_nonpositive_semidefinite(matrix, fix_method="spectral"):
8383
else:
8484
raise NotImplementedError("Method {} not implemented".format(fix_method))
8585

86-
if not _is_positive_semidefinite(fixed_matrix):
87-
warnings.warn("Could not fix matrix. Please try a different risk model.")
86+
if not _is_positive_semidefinite(fixed_matrix): # pragma: no cover
87+
warnings.warn(
88+
"Could not fix matrix. Please try a different risk model.", UserWarning
89+
)
8890

8991
# Rebuild labels if provided
9092
if isinstance(matrix, pd.DataFrame):
@@ -109,7 +111,6 @@ def risk_matrix(prices, method="sample_cov", **kwargs):
109111
- ``sample_cov``
110112
- ``semicovariance``
111113
- ``exp_cov``
112-
- ``min_cov_determinant``
113114
- ``ledoit_wolf``
114115
- ``ledoit_wolf_constant_variance``
115116
- ``ledoit_wolf_single_factor``
@@ -127,8 +128,6 @@ def risk_matrix(prices, method="sample_cov", **kwargs):
127128
return semicovariance(prices, **kwargs)
128129
elif method == "exp_cov":
129130
return exp_cov(prices, **kwargs)
130-
elif method == "min_cov_determinant":
131-
return min_cov_determinant(prices, **kwargs)
132131
elif method == "ledoit_wolf" or method == "ledoit_wolf_constant_variance":
133132
return CovarianceShrinkage(prices, **kwargs).ledoit_wolf()
134133
elif method == "ledoit_wolf_single_factor":
@@ -290,6 +289,8 @@ def min_cov_determinant(
290289
:return: annualised estimate of covariance matrix
291290
:rtype: pd.DataFrame
292291
"""
292+
warnings.warn("min_cov_determinant is deprecated and will be removed in v1.5")
293+
293294
if not isinstance(prices, pd.DataFrame):
294295
warnings.warn("data is not in a dataframe", RuntimeWarning)
295296
prices = pd.DataFrame(prices)
@@ -306,7 +307,8 @@ def min_cov_determinant(
306307
X = prices
307308
else:
308309
X = returns_from_prices(prices)
309-
X = np.nan_to_num(X.values)
310+
# X = np.nan_to_num(X.values)
311+
X = X.dropna().values
310312
raw_cov_array = sklearn.covariance.fast_mcd(X, random_state=random_state)[1]
311313
cov = pd.DataFrame(raw_cov_array, index=assets, columns=assets) * frequency
312314
return fix_nonpositive_semidefinite(cov, kwargs.get("fix_method", "spectral"))
@@ -377,7 +379,7 @@ def __init__(self, prices, returns_data=False, frequency=252):
377379
from sklearn import covariance
378380

379381
self.covariance = covariance
380-
except (ModuleNotFoundError, ImportError):
382+
except (ModuleNotFoundError, ImportError): # pragma: no cover
381383
raise ImportError("Please install scikit-learn via pip or poetry")
382384

383385
if not isinstance(prices, pd.DataFrame):

tests/test_risk_models.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -155,19 +155,20 @@ def test_exp_cov_limits():
155155
assert np.abs(S2 - sample_cov).max().max() < 1e-3
156156

157157

158-
def test_min_cov_det():
159-
df = get_data()
160-
S = risk_models.min_cov_determinant(df, random_state=8)
161-
assert S.shape == (20, 20)
162-
assert S.index.equals(df.columns)
163-
assert S.index.equals(S.columns)
164-
assert S.notnull().all().all()
165-
# assert risk_models._is_positive_semidefinite(S)
166-
# Cover that it works on np.ndarray, with a warning
167-
with pytest.warns(RuntimeWarning):
168-
S2 = risk_models.min_cov_determinant(df.to_numpy(), random_state=8)
169-
assert isinstance(S2, pd.DataFrame)
170-
np.testing.assert_equal(S.to_numpy(), S2.to_numpy())
158+
# def test_min_cov_det():
159+
# df = get_data()
160+
# S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
161+
# S = risk_models.min_cov_determinant(df, random_state=8)
162+
# assert S.shape == (20, 20)
163+
# assert S.index.equals(df.columns)
164+
# assert S.index.equals(S.columns)
165+
# assert S.notnull().all().all()
166+
# # assert risk_models._is_positive_semidefinite(S)
167+
# # Cover that it works on np.ndarray, with a warning
168+
# with pytest.warns(RuntimeWarning):
169+
# S2 = risk_models.min_cov_determinant(df.to_numpy(), random_state=8)
170+
# assert isinstance(S2, pd.DataFrame)
171+
# np.testing.assert_equal(S.to_numpy(), S2.to_numpy())
171172

172173

173174
def test_cov_to_corr():
@@ -311,7 +312,6 @@ def test_risk_matrix_and_returns_data():
311312
"sample_cov",
312313
"semicovariance",
313314
"exp_cov",
314-
# FIXME: this fails "min_cov_determinant",
315315
"ledoit_wolf",
316316
"ledoit_wolf_constant_variance",
317317
"ledoit_wolf_single_factor",

0 commit comments

Comments
 (0)