# Ml

> Use when tasks need optional PyCaret model training, ML factor generation, inference wrappers, feature importance, or sparse LASSO weight generation.

- Skill: `quantskills/ml` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add quantskills/ml`
- Raw SKILL.md: https://api.skillmd.com/api/skills/quantskills/ml/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: quantskills (https://skillmd.com/u/quantskills)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/quantskills/ml

---


# ML

ML contains reusable model training, prediction, ML factor, and sparse fitting
helpers. It should produce predictions, ranks, labels, or weight matrices; return
accounting belongs in `skills.backtest`.

Install model dependencies with `uv sync --extra ml`.

## Public API

```python
from skills.ml.ml_engine import MLEngine, ModelPredictor
from skills.ml.ml_factor import MLFactorEngine, make_precomputed_factor
from skills.ml.lasso_tracker import lasso_track
from skills.ml.pca_fold import fit_fold_transform, make_regressor
from skills.ml.walk_forward import date_level_mask, expanding_purged_folds
```

## Components

| Module | Purpose |
|--------|---------|
| `skills.ml.ml_engine` | Lazy PyCaret classification/regression engine and inference wrapper |
| `skills.ml.ml_factor` | Compress factor configs into ML-ranked cross-sectional factor pivots |
| `skills.ml.lasso_tracker` | Rolling LASSO sparse index-tracking weight generation |
| `skills.ml.pca_fold` | Train-only PCA fold transforms (no StandardScaler) and frozen regressors |
| `skills.ml.walk_forward` | Expanding walk-forward folds with label purge, plus date row masks for `(symbol, eob)` panels |

## Recipes

**ML rank factor for `ModularBacktester`**

```python
from skills.compute import indicators as I
from skills.ml.ml_factor import MLFactorEngine, make_precomputed_factor

engine = MLFactorEngine(
    data=panel_df,
    factor_configs=[
        {"func": I.trend_score_v2, "kwargs": {"period": 24}, "name": "trend"},
        {"func": I.cci, "kwargs": {"period": 48}, "name": "cci"},
    ],
    model_type="xgboost",
    train_mode="rolling",
)
rank_pivot = engine.generate()
ml_factor_fn = make_precomputed_factor(rank_pivot, name="ml_rank")
```

**Expanding purged walk-forward folds**

```python
from skills.ml.walk_forward import expanding_purged_folds

dates = panel.index.get_level_values("eob").unique()
folds = expanding_purged_folds(
    dates,
    min_train=250,
    retrain_step=370,
    purge=20,
)
for fold in folds:
    train_mask = date_level_mask(feature_panel.index, fold.train_dates)
    pred_mask = date_level_mask(feature_panel.index, fold.pred_dates)
```

**Train-only PCA fold transform**

```python
from skills.ml.pca_fold import fit_fold_transform, make_regressor

transform = fit_fold_transform(train_X, pred_X, n_pca=50, random_state=42)
model = make_regressor("lasso")  # or "ols" / "rf" / "xgboost"
model.fit(transform.train_X, train_y)
pred = model.predict(transform.pred_X)
```

**Cross-sectional expanding PCA model scores**

```python
from skills.compute.features import make_logdiff_panel_features
from strategies.cross_sectional.ml_rank import (
    expanding_pca_model_scores,
    expanding_pca_multi_model_scores,
)

features = make_logdiff_panel_features(panel)  # reuse across horizons
# Prefer multi-model so each fold's PCA is fit once:
results = expanding_pca_multi_model_scores(
    panel, models=("ols", "lasso", "rf", "xgboost"), horizon=20, features=features
)
# Or a single model:
result = expanding_pca_model_scores(panel, model="rf", horizon=20, features=features)
scores = result.scores
fold_metrics = result.fold_metrics
overall_metrics = result.overall_metrics
```

**Lesson 07 workflow (18 ETF, equal-weight Top 3)**

```bash
uv run python -m strategies.cross_sectional.workflows.run_lesson07_etf18_logdiff_pca_ml
```

**Sparse index-tracking weights**

```python
from skills.ml.lasso_tracker import lasso_track

weights = lasso_track(
    etf_returns,
    index_returns,
    lookback=120,
    alpha=1e-5,
    rebalance_freq="M",
)
```

**PyCaret classification**

```python
from skills.ml.ml_engine import MLEngine

engine = MLEngine(task="classification", model_name="xgboost")
model, metrics = engine.setup_and_train(train_df, target="label")
preds = engine.predict(test_df)
```

