Audit API¶
The audit module implements the attribute-aware shortcut-potential audit used in the paper: a conditional probe as the single primary test, five secondary detectors, and a conditional permutation null (the attribute shuffled within task-label strata, between patients when patient ids are given). See The paper's audit for the method description.
Running an audit¶
from shortcut_detect.audit import AuditConfig, conditional_audit
cfg = AuditConfig(n_permutations=200, n_permutations_probe=500, seed=42)
result = conditional_audit(E, A, Y, config=cfg, groups=patient_ids)
probe = result.results["probe"]
print(probe.statistic, probe.p_value, probe.p_bh, probe.flag)
Class Reference¶
AuditConfig¶
AuditConfig
dataclass
¶
AuditConfig(
n_permutations: int = 200,
n_permutations_probe: int | None = None,
alpha: float = 0.05,
n_folds: int = 5,
C: float = 1.0,
top_k_fraction: float = 0.05,
n_clusters: int = 8,
n_bootstrap: int = 2000,
max_iter: int = 100,
seed: int = 0,
permutation: str = "within_y",
include_y: bool = True,
detectors: tuple[str, ...] = DETECTORS,
chunk_problems: int = 1200,
cv_repeats: int = 5,
cv_seed: int | None = None,
attribute_level: str = "patient",
)
Settings fixed by the revision method decisions (sections 2 to 4).
conditional_audit¶
conditional_audit
¶
conditional_audit(
E: ndarray,
A: ndarray,
Y: ndarray,
config: AuditConfig | None = None,
groups: ndarray | None = None,
) -> AuditResult
Run the attribute-aware audit on one (embedding, attribute, task) cell.
E is any 2-D float matrix (n, d): any width d and any modality
(image, text, audio, tabular, multimodal encoders), the audit only sees the
numbers. A and Y are 1-D arrays of length n.
groups (e.g. patient ids) makes every cross-validation split
patient-disjoint, every bootstrap resample whole patients, and the
permutation patient-level within Y-pattern strata (see
conditional_permutations).
Source code in shortcut_detect/audit/conditional.py
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 | |
AuditResult¶
AuditResult
dataclass
¶
AuditResult(
n: int,
n_groups: int,
groups: list[str],
group_sizes: dict[str, int],
fold_strata: str,
config: dict[str, Any],
results: dict[str, DetectorResult] = dict(),
n_inconsistent_groups: int = 0,
attribute_level: str = "image",
)
DetectorResult¶
DetectorResult
dataclass
¶
DetectorResult(
detector: str,
statistic: float,
null_mean: float,
null_sd: float,
z: float,
p_value: float,
p_bh: float = float("nan"),
flag: bool = False,
ci_low: float = float("nan"),
ci_high: float = float("nan"),
n_permutations: int = 0,
seconds: float = 0.0,
note: str = "",
repeat_sd: float = float("nan"),
n_repeats: int = 1,
)
conditional_permutations¶
conditional_permutations
¶
conditional_permutations(
a: ndarray,
y: ndarray,
k: int,
rng: Generator,
mode: str = "within_y",
groups: ndarray | None = None,
level: str = "patient",
) -> np.ndarray
Return a (k + 1, n) array whose row 0 is the observed attribute and rows
1..k are permuted copies: within each Y stratum, or globally when
mode='global'.
With groups (patient ids) the permutation unit is the patient, because
images of one patient are correlated and an image-level shuffle gives
anti-conservative p-values.
level='patient': the attribute is a patient property. Each patient's
value (its majority, which is also row 0) is reassigned among patients with
the same Y pattern (all negative, all positive, or mixed).
level='image': the attribute varies between a patient's images (e.g. a
marker). Whole attribute vectors (images ordered by Y) are reassigned among
patients with the same sorted Y vector, hence the same image count, so the
within-patient structure and the joint (A, Y) image counts are kept.
Source code in shortcut_detect/audit/conditional.py
benjamini_hochberg¶
benjamini_hochberg
¶
BH adjusted p-values along the last axis.