Skip to content
GeneratedGenerated from the built extension by scripts/generate_python_api_reference.py; CI fails if it is stale.

openquant.feature_importance

Pure Python. Signatures are as written in the source; descriptions are the docstrings. All Python modules.

MDI, MDA and SFI feature importance (AFML chapter 8) for any scikit-learn-style model.

MDA and SFI are cross-validated, and always on purged k-fold splits built from the label spans t0/t1, which are required (AFML §8.3, and issue #27). There are two ways in:

  • :func:mean_decrease_accuracy and :func:single_feature_importance take an estimator with fit(X, y, sample_weight=...) and predict_proba(X), run the fit/predict loop here in Python, and hand the out-of-sample probabilities to Rust for scoring.
  • :func:mda_from_probabilities and :func:sfi_from_probabilities take those probabilities directly, for a model trained elsewhere on the folds of :func:openquant.cross_validation.purged_kfold_splits with the same arguments.

Either way the scoring, the MDA normalisation and the aggregation are the Rust openquant::feature_importance code. Results map each feature name to {"mean": ..., "std": ...}, where std is the standard error across folds (MDA, SFI) or trees (MDI), in the order of feature_names.

Functions

mda_from_probabilities

mda_from_probabilities(
    y: Any,
    t0: Any,
    t1: Any,
    base_proba: Any,
    permuted_proba: Any,
    *,
    n_splits: int,
    pct_embargo: float = 0.0,
    scoring: str = 'neg_log_loss',
    sample_weight: Any = None,
    feature_names: Sequence[str] | None = None,
    seed: int | None = None,
) -> dict[str, dict[str, float]]

MDA (AFML Snippet 8.3) scored from out-of-sample probabilities of y == 1.

base_proba[i] is the probability for sample i from the model trained on the fold that tests i; permuted_proba[i, j] is the same model's probability after feature j was shuffled within that test fold. The folds are purged_kfold_splits(t0, t1, n_splits, pct_embargo); every sample is tested once. Per fold, a feature's importance is (base - permuted) / (1 - permuted) for accuracy and F1, and (base - permuted) / -permuted for negative log loss. sample_weight weights the scores.

seed is deprecated and passing it emits a DeprecationWarning: the shuffling happened when permuted_proba was computed, so no seed here can change the result.

mean_decrease_accuracy

mean_decrease_accuracy(
    estimator: Any,
    X: Any,
    y: Any,
    t0: Any,
    t1: Any,
    *,
    n_splits: int = 5,
    pct_embargo: float = 0.01,
    scoring: str = 'neg_log_loss',
    sample_weight: Any = None,
    feature_names: Sequence[str] | None = None,
    seed: int = 42,
) -> dict[str, dict[str, float]]

MDA (AFML Snippet 8.3) for a binary classifier with fit and predict_proba.

For each purged fold a copy of estimator (sklearn.base.clone when scikit-learn is installed) is fitted on the training samples with their sample_weight, then each feature column of the test fold is shuffled in turn with numpy.random.default_rng(seed). seed defaults to 42, as in :func:openquant.feature_diagnostics.mda_importance. Labels must be 0/1. See :func:mda_from_probabilities for the scoring.

mean_decrease_impurity

mean_decrease_impurity(
    per_tree_importances: Any,
    feature_names: Sequence[str] | None = None,
) -> dict[str, dict[str, float]]

MDI (AFML Snippet 8.2) from one row of impurity importances per tree.

With scikit-learn: [t.feature_importances_ for t in forest.estimators_]. A zero means the tree never split on the feature and is left out of that feature's mean. Means are normalised to sum to 1. AFML fits the forest with max_features=1 so that every feature gets a chance to be split on.

sfi_from_probabilities

sfi_from_probabilities(
    y: Any,
    t0: Any,
    t1: Any,
    proba: Any,
    *,
    n_splits: int,
    pct_embargo: float = 0.0,
    scoring: str = 'neg_log_loss',
    sample_weight: Any = None,
    feature_names: Sequence[str] | None = None,
) -> dict[str, dict[str, float]]

SFI (AFML Snippet 8.4) scored from out-of-sample probabilities of y == 1.

proba[i, j] is the probability for sample i from a model trained on feature j alone, on the fold of purged_kfold_splits(t0, t1, n_splits, pct_embargo) that tests i. sample_weight weights each fold's score, as in :func:mda_from_probabilities and AFML's cvScore; weight the fit on your side as well.

single_feature_importance

single_feature_importance(
    estimator: Any,
    X: Any,
    y: Any,
    t0: Any,
    t1: Any,
    *,
    n_splits: int = 5,
    pct_embargo: float = 0.01,
    scoring: str = 'neg_log_loss',
    sample_weight: Any = None,
    feature_names: Sequence[str] | None = None,
) -> dict[str, dict[str, float]]

SFI (AFML Snippet 8.4): each feature's out-of-sample score when the model sees only it.

A copy of estimator is fitted per feature and purged fold on that one column, with the training sample_weight. Labels must be 0/1. See :func:sfi_from_probabilities.