walk_forward_mda¶
Defined in fynance.research
- walk_forward_mda(model_factory, X, y, *, train=252, test=63, step=None, purge=0, metric=None, n_repeats=5, seed=0, feature_names=None)[source]
Mean-decrease-accuracy feature importance, evaluated out-of-fold.
Splits
X/ywith the purged walk-forward generatorfynance.data.split.walk_forward. Per fold: fitmodel_factory()once on the train window, score it on the (unpermuted) test window, then – without refitting – for each repeat and each feature, permute that feature’s column within the test window only and re-score. The score drop (baseline - permuted) is the importance signal; it is averaged across folds x repeats (mean ->importances, std ->stds).- Parameters:
- model_factorycallable
Zero-argument callable returning a fresh model exposing
fit(X, y) -> self/predict(X) -> ndarray(fynance.core.SignalModel). Called once per fold, so every fold starts from an untrained model.- Xnumpy.ndarray, shape (n_samples, n_features)
Feature matrix, strictly time-ordered (row
tmust not depend on rows aftert).- ynumpy.ndarray, shape (n_samples,)
Target aligned with
X.- train, testint
Train and test window lengths, forwarded to
walk_forward.- stepint, optional
Roll step (defaults to
test; seewalk_forward).- purgeint
Embargo between train and test windows, forwarded as-is.
- metriccallable, optional
(y_true, y_pred) -> float, higher is better. Defaults to the negative mean squared error (-mean((y_true - y_pred) ** 2)).- n_repeatsint
Number of independent permutation draws per feature per fold.
- seedint
Master seed. Fold
i/ repeatrdraws its permutations fromnumpy.random.default_rng(seed + i * 1000 + r), so the result is fully reproducible for a fixed seed and independent across folds and repeats.- feature_nameslist of str, optional
Labels carried through to
ImportanceResult.feature_names; must matchX.shape[1]if given.
- Returns:
- ImportanceResult
See
ImportanceResult.
- Raises:
- ValueError
If
Xis not 2-D,yis not 1-D, their lengths mismatch,train + testexceeds the number of samples (no fold would fit), orfeature_nameshas the wrong length.
Examples
A closed-form linear model recovers the planted feature (column 0) as the most important, well above the pure-noise columns:
>>> import numpy as np >>> from fynance.research.importance import walk_forward_mda >>> class LinearModel: ... def fit(self, X, y): ... design = np.column_stack([X, np.ones(len(X))]) ... self.coef_, *_ = np.linalg.lstsq(design, y, rcond=None) ... return self ... def predict(self, X): ... design = np.column_stack([X, np.ones(len(X))]) ... return design @ self.coef_ >>> rng = np.random.default_rng(0) >>> n, k = 300, 3 >>> X = rng.standard_normal((n, k)) >>> y = 2.0 * X[:, 0] + 0.1 * rng.standard_normal(n) >>> result = walk_forward_mda(LinearModel, X, y, train=150, test=50, ... n_repeats=3, seed=0) >>> result.n_folds 3 >>> bool(result.importances[0] > result.importances[1]) True >>> bool(result.importances[0] > result.importances[2]) True