<a id="skfolio-moments-oas"></a>

# skfolio.moments.OAS

<a id="skfolio.moments.OAS"></a>

### *class* skfolio.moments.OAS(store_precision=True, assume_centered=False, nearest=True, higham=False, higham_max_iteration=100)

Oracle Approximating Shrinkage Estimator as proposed in [[1]](#re9a22b087643-1).

Read more in [scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.covariance.ShrunkCovariance.html).

* **Parameters:**
  **store_precision** *bool, default=True*
  : Specify if the estimated precision is stored.

  **assume_centered** *bool, default=False*
  : If True, data will not be centered before computation.
    Useful when working with data whose mean is almost, but not exactly
    zero.
    If False (default), data will be centered before computation.
* **Attributes:**
  **covariance_** *ndarray of shape (n_assets, n_assets)*
  : Estimated covariance.

  **location_** *ndarray of shape (n_assets,)*
  : Estimated location, i.e. the estimated mean.

  **precision_** *ndarray of shape (n_assets, n_assets)*
  : Estimated pseudo inverse matrix.
    (stored only if store_precision is True)

  **shrinkage_** *float*
  : Coefficient in the convex combination used for the computation
    of the shrunk estimate. Range is [0, 1].

  **n_features_in_** *int*
  : Number of assets seen during `fit`.

  **feature_names_in_** *ndarray of shape (`n_features_in_`,)*
  : Names of features seen during `fit`. Defined only when `X`
    has feature names that are all strings.

### Methods

| [`error_norm`](#skfolio.moments.OAS.error_norm)(comp_cov[, norm, scaling, squared])   | Compute the Mean Squared Error between two covariance estimators.          |
|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|
| [`fit`](#skfolio.moments.OAS.fit)(X[, y])                                      | Fit the Oracle Approximating Shrinkage covariance model to X.              |
| [`get_metadata_routing`](#skfolio.moments.OAS.get_metadata_routing)()                           | Get metadata routing of this object.                                       |
| [`get_params`](#skfolio.moments.OAS.get_params)([deep])                               | Get parameters for this estimator.                                         |
| [`get_precision`](#skfolio.moments.OAS.get_precision)()                                  | Getter for the precision matrix.                                           |
| [`mahalanobis`](#skfolio.moments.OAS.mahalanobis)(X_test)                              | Compute the squared Mahalanobis distance of observations.                  |
| [`score`](#skfolio.moments.OAS.score)(X_test[, y])                               | Compute the mean log-likelihood of observations under the estimated model. |
| [`set_params`](#skfolio.moments.OAS.set_params)(\*\*params)                           | Set the parameters of this estimator.                                      |
| [`set_score_request`](#skfolio.moments.OAS.set_score_request)()                              | No-op.                                                                     |

### Notes

The regularised covariance is:

(1 - shrinkage) \* cov + shrinkage \* mu \* np.identity(n_features),

where mu = trace(cov) / n_features and shrinkage is given by the OAS formula
(see [[1]](#re9a22b087643-1)).

The shrinkage formulation implemented here differs from Eq. 23 in [[1]](#re9a22b087643-1). In
the original article, formula (23) states that 2/p (p being the number of
features) is multiplied by Trace(cov\*cov) in both the numerator and
denominator, but this operation is omitted because for a large p, the value
of 2/p is so small that it doesn’t affect the value of the estimator.

### References

* <a id='re9a22b087643-1'>**[1]**</a> “Shrinkage algorithms for MMSE covariance estimation”. Chen, Y., Wiesel, A., Eldar, Y. C., & Hero, A. O. IEEE Transactions on Signal Processing, 58(10), 5016-5029, 2010.

<a id="skfolio.moments.OAS.error_norm"></a>

#### error_norm(comp_cov, norm='frobenius', scaling=True, squared=True)

Compute the Mean Squared Error between two covariance estimators.

* **Parameters:**
  **comp_cov** *array-like of shape (n_features, n_features)*
  : The covariance to compare with.

  **norm** *{“frobenius”, “spectral”}, default=”frobenius”*
  : The type of norm used to compute the error. Available error types:
    - ‘frobenius’ (default): sqrt(tr(A^t.A))
    - ‘spectral’: sqrt(max(eigenvalues(A^t.A))
    where A is the error `(comp_cov - self.covariance_)`.

  **scaling** *bool, default=True*
  : If True (default), the squared error norm is divided by n_features.
    If False, the squared error norm is not rescaled.

  **squared** *bool, default=True*
  : Whether to compute the squared error norm or the error norm.
    If True (default), the squared error norm is returned.
    If False, the error norm is returned.
* **Returns:**
  **result** *float*
  : The Mean Squared Error (in the sense of the Frobenius norm) between
    `self` and `comp_cov` covariance estimators.

<a id="skfolio.moments.OAS.fit"></a>

#### fit(X, y=None)

Fit the Oracle Approximating Shrinkage covariance model to X.

* **Parameters:**
  **X** *array-like of shape (n_observations, n_assets)*
  : Price returns of the assets.

  **y** *Ignored*
  : Not used, present for API consistency by convention.
* **Returns:**
  **self** *OAS*
  : Fitted estimator.

<a id="skfolio.moments.OAS.get_metadata_routing"></a>

#### get_metadata_routing()

Get metadata routing of this object.

Please check [User Guide](https://skfolio.org/user_guide/metadata_routing.html.md#metadata-routing) on how the routing
mechanism works.

* **Returns:**
  **routing** *MetadataRequest*
  : A `MetadataRequest` encapsulating
    routing information.

<a id="skfolio.moments.OAS.get_params"></a>

#### get_params(deep=True)

Get parameters for this estimator.

* **Parameters:**
  **deep** *bool, default=True*
  : If True, will return the parameters for this estimator and
    contained subobjects that are estimators.
* **Returns:**
  **params** *dict*
  : Parameter names mapped to their values.

<a id="skfolio.moments.OAS.get_precision"></a>

#### get_precision()

Getter for the precision matrix.

* **Returns:**
  **precision_** *array-like of shape (n_features, n_features)*
  : The precision matrix associated to the current covariance object.

<a id="skfolio.moments.OAS.mahalanobis"></a>

#### mahalanobis(X_test)

Compute the squared Mahalanobis distance of observations.

The squared Mahalanobis distance of an observation $r$ is defined as:

$$
d^2 = (r - \mu)^T \Sigma^{-1} (r - \mu)

$$

where $\Sigma$ is the estimated covariance matrix (`self.covariance_`)
and $\mu$ is the estimated mean (`self.location_` if available, otherwise
zero).

This distance measure accounts for correlations between assets and is useful
for:

* Outlier detection in portfolio returns
* Risk-adjusted distance calculations
* Identifying unusual market regimes

* **Parameters:**
  **X_test** *array-like of shape (n_observations, n_assets) or (n_assets,)*
  : Observations for which to compute the squared Mahalanobis distance.
    Each row represents one observation. If 1D, treated as a single
    observation. Assets with non-finite fitted variance are excluded from
    inference. After this asset-level filtering, each row is evaluated
    using the remaining available values only, covering row-level missing
    values such as market holidays or pre/post-listing. When rows have
    different observation patterns, the returned distances follow
    $\chi^2$ distributions with different degrees of freedom.
    Rows with no finite retained observation return NaN.
* **Returns:**
  **distances** *ndarray of shape (n_observations,) or float*
  : Squared Mahalanobis distance for each observation. Returns a scalar
    if input is 1D.

### Examples

```pycon
>>> import numpy as np
>>> from skfolio.moments import EmpiricalCovariance
>>> rng = np.random.default_rng(0)
>>> X = rng.standard_normal((100, 3))
>>> model = EmpiricalCovariance()
>>> model.fit(X)
EmpiricalCovariance()
>>> distances = model.mahalanobis(X)
>>> # The mean squared distance should be close to the number of assets (3).
>>> print(distances.mean())
2.9...
```

<a id="skfolio.moments.OAS.score"></a>

#### score(X_test, y=None)

Compute the mean log-likelihood of observations under the estimated model.

Evaluates how well the fitted covariance matrix explains new observations,
assuming a multivariate Gaussian distribution. This is useful for:

* Model selection (comparing different covariance estimators)
* Cross-validation of covariance estimation methods
* Assessing goodness-of-fit

The log-likelihood for a single observation $r$ is:

$$
\log p(r | \mu, \Sigma) = -\frac{1}{2} \left[
    n \log(2\pi) + \log|\Sigma| + (r - \mu)^T \Sigma^{-1} (r - \mu)
\right]

$$

where $n$ is the number of assets, $\Sigma$ is the estimated
covariance matrix (`self.covariance_`), and $\mu$ is the estimated
mean (`self.location_` if available, otherwise zero).

* **Parameters:**
  **X_test** *array-like of shape (n_observations, n_assets)*
  : Observations for which to compute the log-likelihood.
    Typically held-out test data not used during fitting.
    Assets with non-finite fitted variance are excluded from inference. This
    typically happens when the fitted covariance cannot be estimated for an
    asset, for example before listing, after delisting, or during a warmup
    period. After this asset-level filtering, each row of `X_test` is scored
    using the remaining available values only. This covers row-level missing
    values in `X_test`, such as market holidays or pre/post-listing.

  **y** *Ignored*
  : Not used, present for scikit-learn API consistency.
* **Returns:**
  **score** *float*
  : Mean log-likelihood of the observations. Higher values indicate better fit.
    The score is averaged over all observations.

### Examples

```pycon
>>> import numpy as np
>>> from skfolio.moments import EmpiricalCovariance, LedoitWolf
>>> rng = np.random.default_rng(0)
>>> X_train = rng.standard_normal((100, 5))
>>> X_test = rng.standard_normal((50, 5))
>>> emp = EmpiricalCovariance().fit(X_train)
>>> lw = LedoitWolf().fit(X_train)
>>> # Compare models on held-out data
>>> print("Empirical:", emp.score(X_test))
Empirical: -6.97...
>>> print("LedoitWolf:", lw.score(X_test))
LedoitWolf: -6.88...
```

<a id="skfolio.moments.OAS.set_params"></a>

#### set_params(\*\*params)

Set the parameters of this estimator.

The method works on simple estimators as well as on nested objects
(such as `Pipeline`). The latter have
parameters of the form `<component>__<parameter>` so that it’s
possible to update each component of a nested object.

* **Parameters:**
  **\*\*params** *dict*
  : Estimator parameters.
* **Returns:**
  **self** *estimator instance*
  : Estimator instance.

<a id="skfolio.moments.OAS.set_score_request"></a>

#### set_score_request()

No-op.

Calling this method has no effect.

* **Returns:**
  **self** *object*
  : The updated object.

