MCPcopy Create free account
hub / github.com/Open-Quant/openquant / substitution_effect_report

Function substitution_effect_report

python/openquant/feature_diagnostics.py:579–706  ·  view source on GitHub ↗
(
    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,
)

Source from the content-addressed store, hash-verified

577
578def _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
589def _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
597def 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:

Callers

nothing calls this directly

Calls 13

_as_matrixFunction · 0.85
_as_vectorFunction · 0.85
_feature_namesFunction · 0.85
_sample_weightFunction · 0.85
_build_intervalsFunction · 0.85
_purged_kfold_splitsFunction · 0.85
mda_importanceFunction · 0.85
_corr_matrixFunction · 0.85
_score_with_perm_groupsFunction · 0.85
_meanFunction · 0.85
_max_abs_offdiagFunction · 0.85

Tested by

no test coverage detected