Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 37 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,27 @@

# Leakly: Leakage checks for any machine-learning pipeline

`Leakly` uses label permutation to test whether a pipeline still performs above
chance when no true signal is present.
`Leakly` uses label permutation to test whether a machine-learning pipeline

If it does, the pipeline may be leaking test-set information
through preprocessing, feature selection, tuning, or another step.
performs above chance when no true signal is present.

## Principle
Above-chance performance after permutation may indicate leakage from

preprocessing, feature selection, tuning, or another step of the pipeline.

## How it works

1. Permute labels to remove the real feature-label association.

2. Run the full pipeline exactly as in the original analysis.

3. Compare the permuted score distribution with chance level.

1. Permute labels to remove real signal.
2. Run the full pipeline exactly as a user would run it.
3. Compare the score distribution with chance level.
4. Above-chance permuted performance suggests possible leakage.

Leakly includes example configurations for a leaky pipeline and a non-leaky
pipeline so users can see the effect immediately.
`Leakly` includes example configurations for a leaky pipeline and a non-leaky

pipeline so users can inspect the effect directly.

![Example permutation AUC summary](https://raw.githubusercontent.com/DeMONLab-BioFINDER/Leakly/main/assets/AUC.png)

Expand All @@ -52,9 +58,7 @@ cd Leakly
pip install -e .
```

## Quick Start

### <a href="https://colab.research.google.com/github/DeMONLab-BioFINDER/Leakly/blob/main/example.ipynb"><img alt="Open example.ipynb in Colab" src="https://img.shields.io/badge/Open-example.ipynb-F9AB00?logo=googlecolab&logoColor=white" height="28"></a>
## Quick Start on Colab: <a href="https://colab.research.google.com/github/DeMONLab-BioFINDER/Leakly/blob/main/example.ipynb"><img alt="Open example.ipynb in Colab" src="https://img.shields.io/badge/Open-example.ipynb-F9AB00?logo=googlecolab&logoColor=white" height="28"></a>

### Key Python snippet

Expand All @@ -63,38 +67,44 @@ from leakly import (
MLPipeline,
SummaryPlotter,
load_example_leakage_config,
permute_label,
)
permute_label)

scores = []
for seed in range(100):
permuted_y = permute_label(data.y, random_state=seed)
permuted_y = permute_label(y, random_state=seed)
score = (
# user could replace with any pipeline
# Replace with any user-defined pipeline
MLPipeline(
data.X,
X,
permuted_y,
covariates=data.covariates,
covariates=covariates,
config=load_example_leakage_config(),
).fit()).evaluate()
).fit()
).evaluate()
scores.append(score)

SummaryPlotter(scores, chance_level=0.5).plot("assets/AUC.png")
SummaryPlotter(scores, chance_level=0.5).plot()
```

## FAQ

**Can Leakly check my own pipeline?**
**Can `Leakly` check my own pipeline?**

Yes. Leakly can evaluate any pipeline that takes `X`, `y`, optional `covariates`, and returns a test score. The key is to run the full pipeline exactly as in the real analysis, including preprocessing, feature selection, tuning, and evaluation.
Yes. `Leakly` can evaluate any pipeline that takes `X`, `y`,
optional `covariates`, and returns a test score.
The key is to run the full pipeline exactly as in the real analysis,
including preprocessing, feature selection, tuning, and evaluation.

**Why can a leaky pipeline score well on permuted labels?**

After label permutation, there should be no real biological, clinical, or statistical link between features and outcomes. A valid pipeline should therefore perform near chance.

A leaky pipeline may still score well if information from the full dataset enters the analysis before the train/test split or outside the cross-validation loop. Common sources include feature selection, scaling, imputation, covariate adjustment, dimensionality reduction, or hyperparameter tuning performed on all samples.
If leakage occurs, information from test samples can enter the analysis before
the train/test split or outside the cross-validation loop. Common sources
include feature selection, scaling, imputation, covariate adjustment,
dimensionality reduction, or hyperparameter tuning performed on all samples.

This is especially problematic in high-dimensional data, such as neuroimaging, omics, or biomarker studies, where random label-specific patterns can appear meaningful by chance. If the test set influences preprocessing or feature selection, the model may "remember" these random patterns and show inflated performance.
In high-dimensional data such as omics and neuroimaging, random features can
appear predictive by chance. If a pipeline can retain these spurious patterns,
it may perform above chance even after labels are permuted.

**How many permutations should I run?**

Expand Down
Binary file modified assets/AUC.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 8 additions & 6 deletions example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
"metadata": {},
"source": [
"## 1. Synthesizing Data\n",
"We will start by synthesizing a dataset that simulates a classification problem. We will use the `simulate_dataset` function from the `Leakly` package to create a dataset with a specified configuration."
"We will start by synthesizing a dataset that simulates a classification problem. We will use the `simulate_dataset` function from the `Leakly` package to create a dataset with a specified configuration.\n",
"\n",
"User can modify the parameters of the dataset to create different scenarios for testing leakage. For example, you can specify the number of samples, features, and the effect size of the features across groups.\n"
]
},
{
Expand All @@ -80,11 +82,11 @@
"simulated_data = simulate_dataset(\n",
" SimulationConfig(\n",
" n_samples=200, # number of samples in the dataset\n",
" n_features=1000, # number of features in the dataset\n",
" n_features=1000, # number of features => mimic high-dimensional data\n",
" n_covariates=3, # number of covariates in the dataset\n",
" effect_fraction=0.1, # fraction of features that have an effect\n",
" effect_size=0.5, # size of the effect for the informative features\n",
" class_balance=0.5, # proportion of positive class\n",
" effect_fraction=0.3, # fraction of features that have an effect\n",
" effect_size=0.3, # size of the effect for the informative features\n",
" class_balance=0.3, # proportion of positive class\n",
" random_state=42, # random seed for reproducibility\n",
" )\n",
")\n",
Expand Down Expand Up @@ -218,7 +220,7 @@
"from leakly import SummaryPlotter\n",
"\n",
"leakage_plotter = SummaryPlotter(leakage_permuted_scores, chance_level=0.5)\n",
"leakage_plotter.plot()\n",
"leakage_plotter.plot('./assets/AUC.png')\n",
"\n",
"nonlocal_plotter = SummaryPlotter(nonleakage_permuted_scores, chance_level=0.5)\n",
"nonlocal_plotter.plot()"
Expand Down
Loading