leakhound-ml 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ .venv/
7
+ venv/
8
+ .pytest_cache/
9
+ .DS_Store
@@ -0,0 +1,348 @@
1
+ # Getting Started with LeakHound
2
+
3
+ A complete, copy-paste guide — from zero to your first leakage report — on
4
+ **Windows, macOS and Linux**. No prior experience assumed. If you can open a
5
+ terminal and paste a line, you can run this.
6
+
7
+ > **What it does, in one sentence:** you give LeakHound your training and test
8
+ > files, and it tells you whether your model's score is real — and how much of it
9
+ > is fake — by finding the ways the test set was contaminated by the training data.
10
+
11
+ ---
12
+
13
+ ## Table of contents
14
+
15
+ 1. [Do you have Python?](#1-do-you-have-python)
16
+ 2. [Install LeakHound](#2-install-leakhound)
17
+ 3. [Run your first check (sample data included)](#3-run-your-first-check)
18
+ 4. [Run it on your own data](#4-run-it-on-your-own-data)
19
+ 5. [Read the report](#5-read-the-report)
20
+ 6. [Fix each kind of leak](#6-fix-each-kind-of-leak)
21
+ 7. [Measure the damage (`--measure-impact`)](#7-measure-the-damage)
22
+ 8. [Auto mode (`--auto`)](#8-auto-mode)
23
+ 9. [Shareable HTML report (`--html`)](#9-shareable-html-report)
24
+ 10. [Use it from Python](#10-use-it-from-python)
25
+ 11. [Use it in CI (fail a bad merge)](#11-use-it-in-ci)
26
+ 12. [Troubleshooting](#12-troubleshooting)
27
+ 13. [FAQ](#13-faq)
28
+
29
+ ---
30
+
31
+ ## 1. Do you have Python?
32
+
33
+ LeakHound needs **Python 3.9 or newer**. Check it first.
34
+
35
+ **Windows** (Command Prompt or PowerShell):
36
+ ```bat
37
+ python --version
38
+ ```
39
+ **macOS / Linux** (Terminal):
40
+ ```bash
41
+ python3 --version
42
+ ```
43
+
44
+ If you see something like `Python 3.11.5`, you're set — skip to step 2.
45
+ If not, install Python:
46
+
47
+ - **Windows:** download from <https://www.python.org/downloads/> and, on the
48
+ first installer screen, **tick "Add python.exe to PATH"**. (Or run
49
+ `winget install Python.Python.3.12`.)
50
+ - **macOS:** `brew install python`, or download from python.org.
51
+ - **Linux (Debian/Ubuntu/Pop!_OS):** `sudo apt install python3 python3-pip`
52
+
53
+ ---
54
+
55
+ ## 2. Install LeakHound
56
+
57
+ > While LeakHound is pre-release, install it from source. Once it's published,
58
+ > `pip install leakhound` will be all you need.
59
+
60
+ ```bash
61
+ git clone https://github.com/happyhellpt/leakhound.git
62
+ cd leakhound
63
+ pip install -e '.[impact]'
64
+ ```
65
+
66
+ `[impact]` also installs scikit-learn, which powers the `--measure-impact`
67
+ feature (step 7). Leave it out (`pip install -e .`) if you only want the
68
+ detectors.
69
+
70
+ On Windows, if `pip` isn't found, use `py -m pip install -e ".[impact]"`.
71
+
72
+ Check it works:
73
+ ```bash
74
+ leakhound --version
75
+ ```
76
+
77
+ > If `leakhound` is "not found" after install, you can always run it as
78
+ > `python -m leakhound.cli ...` — see [Troubleshooting](#12-troubleshooting).
79
+
80
+ ---
81
+
82
+ ## 3. Run your first check
83
+
84
+ The repo ships with example data that already contains planted leaks. From inside
85
+ the `leakhound` folder:
86
+
87
+ ```bash
88
+ leakhound --train examples/train_sample.csv --test examples/test_sample.csv --target label --time-col date --group-col patient_id
89
+ ```
90
+
91
+ You'll see (trimmed):
92
+
93
+ ```
94
+ LeakHound report
95
+ ────────────────────────────────────────────────
96
+ ✗ [high ] duplicates: 12 test rows (13.3%) also appear in training — the model has seen them
97
+ → fix: Remove duplicates before splitting (df.drop_duplicates()) ...
98
+ ✗ [high ] target_encoding: feature 'leaky_feature' correlates 1.000 with the target — it likely leaks it
99
+ → fix: Drop this feature, or replace it with information available at prediction time.
100
+ ✗ [high ] temporal: 168 training rows (100.0%) are dated at/after the earliest test row — the model trains on the future
101
+ → fix: Split chronologically: sort by the time column and put later rows in test.
102
+ ✗ [high ] group_split: 49 values of 'patient_id' (89.1% of test groups) are in both sets ...
103
+ → fix: Use a group-aware splitter (GroupShuffleSplit / GroupKFold) ...
104
+ ! [medium] near_duplicates: 5 test rows (5.6%) are near-identical to training rows ...
105
+ ────────────────────────────────────────────────
106
+ 5 likely leaks found. Your reported metric is probably optimistic.
107
+ ```
108
+
109
+ That's it — you just ran LeakHound. 🎉 Every finding tells you what it found **and
110
+ how to fix it**.
111
+
112
+ ---
113
+
114
+ ## 4. Run it on your own data
115
+
116
+ You need **two CSV files**: your training set and your test (or validation) set,
117
+ each with a header row. Then:
118
+
119
+ ```bash
120
+ leakhound --train path/to/train.csv --test path/to/test.csv --target label
121
+ ```
122
+
123
+ Add the optional flags when your data has them — each switches on more:
124
+
125
+ | Flag | Give it | Turns on |
126
+ |---|---|---|
127
+ | `--train` (required) | your training CSV | — |
128
+ | `--test` | your test/validation CSV | duplicate + near-duplicate checks |
129
+ | `--target` | the column you're predicting | target-encoding check |
130
+ | `--time-col` | a date/timestamp column | look-ahead (temporal) check |
131
+ | `--group-col` | an id column (patient, user, device) | group-split check |
132
+ | `--measure-impact` | *(no value)* | quantify how much each leak inflates the score |
133
+ | `--auto` | *(no value)* | auto-detect the columns above / advise on one file |
134
+ | `--html PATH` | a file path | also write a shareable HTML report |
135
+ | `--ascii` | *(no value)* | plain-text output for old terminals |
136
+
137
+ Only the checks whose inputs you provide will run.
138
+
139
+ ---
140
+
141
+ ## 5. Read the report
142
+
143
+ Each line is one finding, with a severity, the evidence, and a fix.
144
+
145
+ - **`✗ high`** — almost certainly real leakage. Fix before trusting any score.
146
+ - **`! medium`** — likely leakage; worth investigating.
147
+ - **`· low`** — informational (e.g. a check couldn't run).
148
+ - **`✓ ok`** — that specific check found nothing.
149
+
150
+ | Check | What it means |
151
+ |---|---|
152
+ | **duplicates** | Exact same rows in both train and test — tested on memorised data. |
153
+ | **near_duplicates** | Rows identical after tiny rounding — copies you didn't notice. |
154
+ | **temporal** | Training rows dated at/after your test rows — the model "saw the future". |
155
+ | **target_encoding** | A feature (often an ID) basically *is* the answer. |
156
+ | **group_split** | The same subject is in both sets — it recognises the subject, not the pattern. |
157
+ | **impact** | *How much* score each leak is inflating (see step 7). |
158
+
159
+ > ⚠️ A clean report is **not proof** your split is perfect. It means these
160
+ > common, high-impact leaks aren't present.
161
+
162
+ ---
163
+
164
+ ## 6. Fix each kind of leak
165
+
166
+ **Duplicates / near-duplicates across train/test**
167
+ ```python
168
+ df = df.drop_duplicates() # then split once, cleanly
169
+ ```
170
+ Also check your pipeline for copied or augmented rows.
171
+
172
+ **Temporal (look-ahead) leakage** — split by time, not randomly:
173
+ ```python
174
+ df = df.sort_values("date")
175
+ cut = int(len(df) * 0.8)
176
+ train, test = df.iloc[:cut], df.iloc[cut:]
177
+ ```
178
+
179
+ **Target-encoding leakage** — drop the leaking feature (often an ID or a value
180
+ recorded *after* the outcome):
181
+ ```python
182
+ train = train.drop(columns=["leaky_feature"])
183
+ test = test.drop(columns=["leaky_feature"])
184
+ ```
185
+
186
+ **Group split leakage** — keep every group on one side:
187
+ ```python
188
+ from sklearn.model_selection import GroupShuffleSplit
189
+ splitter = GroupShuffleSplit(test_size=0.2, random_state=0)
190
+ train_idx, test_idx = next(splitter.split(X, y, groups=df["patient_id"]))
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 7. Measure the damage
196
+
197
+ Detecting a leak is one thing; seeing what it's worth is another. Add
198
+ `--measure-impact` and LeakHound fits a quick baseline model, then reports your
199
+ honest score next to the inflated one:
200
+
201
+ ```bash
202
+ leakhound --train examples/train_sample.csv --test examples/test_sample.csv --target label --measure-impact
203
+ ```
204
+
205
+ ```
206
+ ✗ [high ] impact: removing leaking feature(s) ['leaky_feature'] drops AUC from 1.000 to 0.669 — +0.331 of fake performance
207
+ AUC_with_leak: 1.0
208
+ AUC_without_leak: 0.669
209
+ inflation: 0.331
210
+ → fix: Drop the leaking feature(s) and re-evaluate honestly.
211
+ ```
212
+
213
+ Your `1.000` was really `0.669`. It works for **binary** (0/1) and **continuous**
214
+ targets (AUC and R² respectively), using numeric features. Needs scikit-learn
215
+ (`pip install 'leakhound[impact]'`). Treat the number as a quick baseline
216
+ estimate, not gospel.
217
+
218
+ ---
219
+
220
+ ## 8. Auto mode
221
+
222
+ Not sure which columns are the target, the timestamp or the group id? Add
223
+ `--auto` and LeakHound guesses them:
224
+
225
+ ```bash
226
+ leakhound --train examples/train_sample.csv --auto
227
+ ```
228
+
229
+ ```
230
+ Auto-detected -> target='label', time_col='date', group_col='patient_id'
231
+ ...
232
+ ! [medium] temporal: column 'date' looks like a time column — a random split would let the model train on the future
233
+ ! [medium] group_split: column 'patient_id' looks like a group id — a random split would put the same group on both sides
234
+ ```
235
+
236
+ Run on a **single file** (no `--test`), it becomes a *pre-split linter*: it warns
237
+ you which columns will leak **before** you split. Run it with a test set too and
238
+ it just fills in any columns you didn't name.
239
+
240
+ ---
241
+
242
+ ## 9. Shareable HTML report
243
+
244
+ Add `--html` to also write a self-contained report you can send to a colleague or
245
+ attach to a pull request (no internet or extra files needed to open it):
246
+
247
+ ```bash
248
+ leakhound --train train.csv --test test.csv --target label --measure-impact --html leakhound_report.html
249
+ ```
250
+
251
+ Open `leakhound_report.html` in any browser. It adapts to light and dark mode.
252
+
253
+ ---
254
+
255
+ ## 10. Use it from Python
256
+
257
+ ```python
258
+ import pandas as pd
259
+ from leakhound import audit
260
+
261
+ train = pd.read_csv("train.csv")
262
+ test = pd.read_csv("test.csv")
263
+
264
+ report = audit(train, test, target="label", time_col="date",
265
+ group_col="patient_id", measure_impact=True)
266
+ print(report.render())
267
+
268
+ # Save the shareable report
269
+ with open("report.html", "w", encoding="utf-8") as f:
270
+ f.write(report.to_html())
271
+
272
+ if not report.clean:
273
+ raise SystemExit("Leakage detected — fix the split before training.")
274
+ ```
275
+
276
+ `report.leaks` gives the findings as objects (`.check`, `.severity`, `.message`,
277
+ `.evidence`, `.fix`).
278
+
279
+ ---
280
+
281
+ ## 11. Use it in CI
282
+
283
+ LeakHound exits non-zero when it finds leakage, so it can **fail a pull request**
284
+ that would ship a contaminated split (`.github/workflows/leakhound.yml`):
285
+
286
+ ```yaml
287
+ name: data-leakage-check
288
+ on: [push, pull_request]
289
+ jobs:
290
+ leakhound:
291
+ runs-on: ubuntu-latest
292
+ steps:
293
+ - uses: actions/checkout@v4
294
+ - uses: actions/setup-python@v5
295
+ with:
296
+ python-version: "3.12"
297
+ - run: pip install 'leakhound[impact]'
298
+ - run: leakhound --train data/train.csv --test data/test.csv --target label --measure-impact
299
+ ```
300
+
301
+ If a leak is found, the step fails and the merge is blocked.
302
+
303
+ ---
304
+
305
+ ## 12. Troubleshooting
306
+
307
+ **`leakhound: command not found`** — run it as a module instead:
308
+ ```bash
309
+ python -m leakhound.cli --train examples/train_sample.csv --test examples/test_sample.csv --target label
310
+ ```
311
+
312
+ **`install scikit-learn to measure leak impact`** — `--measure-impact` needs it:
313
+ ```bash
314
+ pip install 'leakhound[impact]'
315
+ ```
316
+
317
+ **`FileNotFoundError`** — wrong path. Use the full path, or `cd` into the folder
318
+ first. On Windows, paths use backslashes: `data\train.csv`.
319
+
320
+ **Strange symbols / `UnicodeEncodeError` on Windows** — old `cmd.exe` can't print
321
+ the report symbols. Add `--ascii` (LeakHound auto-detects this in most cases):
322
+ ```bat
323
+ leakhound --train train.csv --test test.csv --target label --ascii
324
+ ```
325
+
326
+ **`UnicodeDecodeError` reading the CSV** — re-save your CSV as UTF-8.
327
+
328
+ **`target 'label' not found`** — the `--target` name must match a column header
329
+ exactly (case-sensitive). Or use `--auto` to let LeakHound guess it.
330
+
331
+ ---
332
+
333
+ ## 13. FAQ
334
+
335
+ **Does LeakHound change my data?** No. It only reads your files and prints a
336
+ report. It never writes to them (except the `--html` file you ask for).
337
+
338
+ **Does a clean report guarantee my model is fine?** No. It rules out the most
339
+ common, highest-impact leaks — not every possible one.
340
+
341
+ **Which operating systems are supported?** Windows, macOS and Linux, identically
342
+ (bar the `python` vs `python3` detail in step 1).
343
+
344
+ **What file formats does it read?** CSV, for now. Data is loaded into memory with
345
+ pandas, so very large files need enough RAM.
346
+
347
+ **Can I run just one check?** Yes — only supply the inputs for the checks you
348
+ want.