ML4T Diagnostic
ML4T Diagnostic Documentation
Feature validation, strategy diagnostics, and Deflated Sharpe Ratio
Skip to content

Feature Selection

FeatureSelector applies explicit filters to evaluated features. It consumes FeatureOutcomeResult; it does not fit a model or compute IC values itself.

Filter by IC and correlation

import polars as pl

from ml4t.diagnostic.selection import FeatureSelector
from ml4t.diagnostic.selection.types import FeatureICResults, FeatureOutcomeResult

features = ["momentum_5d", "momentum_20d", "volatility", "noise"]
mean_ic = {
    "momentum_5d": 0.045,
    "momentum_20d": 0.038,
    "volatility": -0.030,
    "noise": 0.004,
}
ic_results = {
    feature: FeatureICResults(
        feature=feature,
        ic_mean=value,
        ic_std=0.02,
        ic_ir=value / 0.02,
        t_stat=value / 0.01,
        p_value=0.01 if abs(value) >= 0.02 else 0.60,
        ic_by_lag={1: value},
        n_observations=120,
    )
    for feature, value in mean_ic.items()
}
outcomes = FeatureOutcomeResult(features=features, ic_results=ic_results)
correlations = pl.DataFrame(
    {
        "feature": features,
        "momentum_5d": [1.0, 0.92, 0.10, 0.02],
        "momentum_20d": [0.92, 1.0, 0.12, 0.01],
        "volatility": [0.10, 0.12, 1.0, 0.05],
        "noise": [0.02, 0.01, 0.05, 1.0],
    }
)

selector = FeatureSelector(outcomes, correlations)
selector.run_pipeline(
    [
        ("ic", {"threshold": 0.02, "min_periods": 60}),
        ("correlation", {"threshold": 0.80, "keep_strategy": "higher_ic"}),
    ]
)

report = selector.get_selection_report()
print(f"Selected: {report.final_features}")
print(f"Removed: {selector.get_removed_features()}")

The IC filter uses absolute IC, so a stable negative relation can survive. The correlation filter above keeps the member of each correlated pair with the larger absolute IC.

Available filters

Filter name Required results
ic FeatureICResults
importance FeatureImportanceResults
correlation Correlation matrix
drift Drift results on FeatureOutcomeResult

Record thresholds and the final SelectionReport with each model run. Feature selection on the full dataset leaks information; compute its inputs within the training portion of each cross-validation fold.