(
X: Sequence[Sequence[float]],
y: Sequence[float],
feature_names: Sequence[str] | None = None,
sample_weight: Sequence[float] | None = None,
event_end_indices: Sequence[int] | None = None,
n_splits: int = 5,
pct_embargo: float = 0.01,
scoring: str = "neg_log_loss",
corr_threshold: float = 0.9,
orthogonalize: bool = True,
)
| 577 | |
| 578 | def _corr_matrix(x: Sequence[Sequence[float]]) -> list[list[float]]: |
| 579 | z, _, _ = _standardize(x) |
| 580 | n = len(z) |
| 581 | p = len(z[0]) |
| 582 | corr = [[0.0 for _ in range(p)] for _ in range(p)] |
| 583 | for i in range(p): |
| 584 | for j in range(p): |
| 585 | corr[i][j] = sum(row[i] * row[j] for row in z) / max(n - 1, 1) |
| 586 | return corr |
| 587 | |
| 588 | |
| 589 | def _max_abs_offdiag(m: Sequence[Sequence[float]]) -> float: |
| 590 | n = len(m) |
| 591 | if n <= 1: |
| 592 | return 0.0 |
| 593 | vals = [abs(m[i][j]) for i in range(n) for j in range(n) if i != j] |
| 594 | return max(vals) if vals else 0.0 |
| 595 | |
| 596 | |
| 597 | def substitution_effect_report( |
| 598 | X: Sequence[Sequence[float]], |
| 599 | y: Sequence[float], |
| 600 | feature_names: Sequence[str] | None = None, |
| 601 | sample_weight: Sequence[float] | None = None, |
| 602 | event_end_indices: Sequence[int] | None = None, |
| 603 | n_splits: int = 5, |
| 604 | pct_embargo: float = 0.01, |
| 605 | scoring: str = "neg_log_loss", |
| 606 | corr_threshold: float = 0.9, |
| 607 | orthogonalize: bool = True, |
| 608 | allow_unpurged: bool = False, |
| 609 | ) -> dict[str, object]: |
| 610 | x = _as_matrix(X) |
| 611 | yv = _as_vector(y, len(x)) |
| 612 | names = _feature_names(len(x[0]), feature_names) |
| 613 | weights = _sample_weight(sample_weight, len(x)) |
| 614 | intervals = _build_intervals(event_end_indices, len(x), allow_unpurged=allow_unpurged) |
| 615 | splits = _purged_kfold_splits(intervals, n_splits=n_splits, pct_embargo=pct_embargo) |
| 616 | |
| 617 | mda = mda_importance( |
| 618 | x, |
| 619 | yv, |
| 620 | feature_names=names, |
| 621 | sample_weight=weights, |
| 622 | event_end_indices=event_end_indices, |
| 623 | n_splits=n_splits, |
| 624 | pct_embargo=pct_embargo, |
| 625 | scoring=scoring, |
| 626 | allow_unpurged=allow_unpurged, |
| 627 | ) |
| 628 | base_table: pl.DataFrame = mda["table"] |
| 629 | base_map = {row["feature"]: float(row["mean"]) for row in base_table.to_dicts()} |
| 630 | |
| 631 | corr = _corr_matrix(x) |
| 632 | pairs: list[dict[str, Any]] = [] |
| 633 | for i in range(len(names)): |
| 634 | for j in range(i + 1, len(names)): |
| 635 | corr_ij = corr[i][j] |
| 636 | if abs(corr_ij) < corr_threshold: |
nothing calls this directly
no test coverage detected