itbound 0.1.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.
- itbound-0.1.0/PKG-INFO +508 -0
- itbound-0.1.0/README.md +487 -0
- itbound-0.1.0/pyproject.toml +43 -0
- itbound-0.1.0/setup.cfg +4 -0
- itbound-0.1.0/src/fbound/__init__.py +1 -0
- itbound-0.1.0/src/fbound/estimators/__init__.py +17 -0
- itbound-0.1.0/src/fbound/estimators/causal_bound.py +1533 -0
- itbound-0.1.0/src/fbound/utils/__init__.py +32 -0
- itbound-0.1.0/src/fbound/utils/data_generating.py +471 -0
- itbound-0.1.0/src/fbound/utils/divergences.py +523 -0
- itbound-0.1.0/src/fbound/utils/models.py +312 -0
- itbound-0.1.0/src/fbound/utils/plotting.py +11 -0
- itbound-0.1.0/src/fbound/utils/result.py +18 -0
- itbound-0.1.0/src/fbound/utils/utils.py +199 -0
- itbound-0.1.0/src/itbound/__init__.py +22 -0
- itbound-0.1.0/src/itbound/__main__.py +5 -0
- itbound-0.1.0/src/itbound/api.py +219 -0
- itbound-0.1.0/src/itbound/artifacts.py +361 -0
- itbound-0.1.0/src/itbound/claims.py +176 -0
- itbound-0.1.0/src/itbound/cli.py +562 -0
- itbound-0.1.0/src/itbound/config.py +163 -0
- itbound-0.1.0/src/itbound/live_demo.py +336 -0
- itbound-0.1.0/src/itbound/plotting.py +93 -0
- itbound-0.1.0/src/itbound/report.py +108 -0
- itbound-0.1.0/src/itbound/reproduce_final_arxiv_plots.py +293 -0
- itbound-0.1.0/src/itbound/standard.py +622 -0
- itbound-0.1.0/src/itbound.egg-info/PKG-INFO +508 -0
- itbound-0.1.0/src/itbound.egg-info/SOURCES.txt +59 -0
- itbound-0.1.0/src/itbound.egg-info/dependency_links.txt +1 -0
- itbound-0.1.0/src/itbound.egg-info/entry_points.txt +2 -0
- itbound-0.1.0/src/itbound.egg-info/requires.txt +14 -0
- itbound-0.1.0/src/itbound.egg-info/top_level.txt +2 -0
- itbound-0.1.0/tests/test_agents_p0_validity.py +135 -0
- itbound-0.1.0/tests/test_aggregation_p0.py +78 -0
- itbound-0.1.0/tests/test_artifact_contract.py +97 -0
- itbound-0.1.0/tests/test_batching.py +28 -0
- itbound-0.1.0/tests/test_claims_engine.py +63 -0
- itbound-0.1.0/tests/test_cli_demo.py +237 -0
- itbound-0.1.0/tests/test_cli_example.py +28 -0
- itbound-0.1.0/tests/test_cli_quick.py +144 -0
- itbound-0.1.0/tests/test_cli_reproduce.py +38 -0
- itbound-0.1.0/tests/test_cli_run.py +89 -0
- itbound-0.1.0/tests/test_config_validation.py +8 -0
- itbound-0.1.0/tests/test_docs_assets.py +11 -0
- itbound-0.1.0/tests/test_fit_api.py +129 -0
- itbound-0.1.0/tests/test_import_itbound.py +6 -0
- itbound-0.1.0/tests/test_packaging_metadata_contract.py +20 -0
- itbound-0.1.0/tests/test_plotting.py +109 -0
- itbound-0.1.0/tests/test_readme_pypi_rendering.py +22 -0
- itbound-0.1.0/tests/test_release_ci_contract.py +32 -0
- itbound-0.1.0/tests/test_release_docs_contract.py +28 -0
- itbound-0.1.0/tests/test_release_external_ops_contract.py +27 -0
- itbound-0.1.0/tests/test_release_gate_rehearsal_contract.py +39 -0
- itbound-0.1.0/tests/test_release_gitignore_contract.py +10 -0
- itbound-0.1.0/tests/test_release_pipeline_contract.py +36 -0
- itbound-0.1.0/tests/test_release_preflight_contract.py +23 -0
- itbound-0.1.0/tests/test_release_runbook_postrelease_contract.py +12 -0
- itbound-0.1.0/tests/test_release_version_sync_contract.py +23 -0
- itbound-0.1.0/tests/test_smoke_gate.py +142 -0
- itbound-0.1.0/tests/test_standard_library.py +393 -0
- itbound-0.1.0/tests/test_trust_pack_regression.py +97 -0
itbound-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: itbound
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Data-driven information-theoretic causal bounds under unmeasured confounding.
|
|
5
|
+
Author: Yonghan Jung, Jiwoong Kang
|
|
6
|
+
Keywords: causal-inference,partial-identification,bounds,f-divergence
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: numpy
|
|
10
|
+
Requires-Dist: pandas
|
|
11
|
+
Requires-Dist: torch
|
|
12
|
+
Requires-Dist: scikit-learn
|
|
13
|
+
Requires-Dist: pyyaml
|
|
14
|
+
Provides-Extra: experiments
|
|
15
|
+
Requires-Dist: matplotlib; extra == "experiments"
|
|
16
|
+
Requires-Dist: scipy; extra == "experiments"
|
|
17
|
+
Requires-Dist: statsmodels; extra == "experiments"
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest; extra == "dev"
|
|
20
|
+
Requires-Dist: build; extra == "dev"
|
|
21
|
+
|
|
22
|
+
# Information-Theoretic Causal Bounds under Unmeasured Confounding
|
|
23
|
+
|
|
24
|
+
This repo implements the method in "Information-Theoretic Causal Bounds under Unmeasured Confounding (Jung & Kang, 2026)." It provides lower and upper bounds on causal estimands under unmeasured confounding without bounded outcomes, sensitivity parameters, instruments/proxies, or full SCM specification.
|
|
25
|
+
|
|
26
|
+
Target estimands (paper notation):
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
θ(a, x) = E_{Q_{a,x}}[φ(Y)], Q_{a,x} = P(Y | do(A=a), X=x)
|
|
30
|
+
θ(a) = E_{Q_a}[φ(Y)]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Install (step-by-step, very detailed)
|
|
34
|
+
|
|
35
|
+
Below is a public, copy‑paste friendly guide. The key idea is that `pip install .` installs the package from the **current directory** (this repo) into your **currently active Python environment**.
|
|
36
|
+
|
|
37
|
+
### 0) Open a terminal and go to the repo root
|
|
38
|
+
|
|
39
|
+
You must run these commands **in the repository root** (the folder containing `pyproject.toml`).
|
|
40
|
+
|
|
41
|
+
If you haven’t cloned the repo yet:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
git clone https://github.com/yonghanjung/Information-Theretic-Bounds.git
|
|
45
|
+
cd Information-Theretic-Bounds
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If you already have the repo locally, just `cd` into it:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd <your-local-repo-path>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Check you are in the right place:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
ls pyproject.toml
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If it prints `pyproject.toml`, you are in the correct directory.
|
|
61
|
+
|
|
62
|
+
### 1) Create and activate a clean virtual environment (recommended)
|
|
63
|
+
|
|
64
|
+
This keeps dependencies isolated to this project.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python -m venv .venv
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Activate it:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
source .venv/bin/activate # macOS/Linux
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
On Windows (PowerShell):
|
|
77
|
+
|
|
78
|
+
```powershell
|
|
79
|
+
.venv\\Scripts\\Activate.ps1
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
On Windows (cmd.exe):
|
|
83
|
+
|
|
84
|
+
```bat
|
|
85
|
+
.venv\\Scripts\\activate.bat
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
After activation, your shell prompt usually shows `(.venv)`.
|
|
89
|
+
|
|
90
|
+
### 2) Upgrade pip inside the venv
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python -m pip install --upgrade pip
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 3) Install this package from the repo directory
|
|
97
|
+
|
|
98
|
+
This installs **itbound** into the active environment.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python -m pip install .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
What this means:
|
|
105
|
+
- `.` means “the current folder.”
|
|
106
|
+
- So `pip install .` tells pip to read `pyproject.toml` here and install the package.
|
|
107
|
+
|
|
108
|
+
### 4) (Optional) Development install (editable)
|
|
109
|
+
|
|
110
|
+
Use this if you want local code changes to be reflected immediately without reinstalling.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
python -m pip install -e .
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 5) (Optional) Extras for figure reproduction
|
|
117
|
+
|
|
118
|
+
If you want to run the `reproduce` command and create figures:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python -m pip install '.[experiments]'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 6) Quick sanity check
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
python -m itbound --help
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If you see the CLI help output, the installation worked.
|
|
131
|
+
|
|
132
|
+
## 10-Minute Quickstart (Opt-in Wrapper)
|
|
133
|
+
|
|
134
|
+
`quick` is an opt-in wrapper around `itbound.fit(...)`; default math remains paper-equivalent (`mode=paper-default`).
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
python -m venv .venv && source .venv/bin/activate
|
|
138
|
+
python -m pip install --upgrade pip
|
|
139
|
+
python -m pip install .
|
|
140
|
+
python -m itbound example --out /tmp/itbound_example.csv
|
|
141
|
+
python -m itbound quick --data /tmp/itbound_example.csv --treatment a --outcome y --covariates x1,x2 --outdir /tmp/itbound_quick
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
What the outputs mean:
|
|
145
|
+
- `lower`/`upper`: robust causal bound endpoints, not a single identified point estimate.
|
|
146
|
+
- `width = upper - lower`: interval uncertainty under the allowed confounding set.
|
|
147
|
+
- `valid_interval`: whether each row has a finite valid interval after domain/validity checks.
|
|
148
|
+
|
|
149
|
+
Artifact location:
|
|
150
|
+
- All quick outputs are written under `--outdir` (for example `/tmp/itbound_quick`).
|
|
151
|
+
- Expected files: `summary.txt`, `results.json`, `claims.json`, `claims.md`, `plots/`, optional `report.html`.
|
|
152
|
+
- Details: [`docs/quickstart.md`](docs/quickstart.md), [`docs/artifact_contract.md`](docs/artifact_contract.md), schema [`docs/results_schema_v0.md`](docs/results_schema_v0.md).
|
|
153
|
+
|
|
154
|
+
## Python API
|
|
155
|
+
|
|
156
|
+
New wrapper (recommended):
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import itbound
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Standard-library function:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from itbound.standard import run_standard_bounds
|
|
166
|
+
|
|
167
|
+
result = run_standard_bounds(
|
|
168
|
+
csv_path="/tmp/itbound_toy.csv",
|
|
169
|
+
outcome_col="y",
|
|
170
|
+
treatment_col="a",
|
|
171
|
+
covariate_cols=["x1", "x2"],
|
|
172
|
+
divergences=["KL", "JS", "Hellinger", "TV", "Chi2"],
|
|
173
|
+
aggregation_mode="paper_adaptive_k",
|
|
174
|
+
outdir="/tmp/itbound_standard",
|
|
175
|
+
write_html=True,
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Legacy import (still supported):
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
import fbound
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## CLI
|
|
186
|
+
|
|
187
|
+
### Run bounds from config
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
itbound run --config docs/cli-config.example.yaml
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
You can override output path:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
itbound run --config docs/cli-config.example.yaml --out /tmp/itbound_bounds.csv
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Run a quick synthetic example
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
itbound example --out /tmp/itbound_example.csv
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Reproduce arXiv plots
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
itbound reproduce --dry-run
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Notes:
|
|
212
|
+
- `reproduce` expects the final-arxiv JSON summaries under `experiments/final-arxiv`.
|
|
213
|
+
- If you installed the package, run `itbound reproduce` from the repo root so the data files are found.
|
|
214
|
+
- Install extras first: `pip install .[experiments]`.
|
|
215
|
+
|
|
216
|
+
### Standard-library run (CSV -> bounds + claims JSON + plots + optional HTML)
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
itbound standard \
|
|
220
|
+
--csv /tmp/itbound_toy.csv \
|
|
221
|
+
--y-col y \
|
|
222
|
+
--a-col a \
|
|
223
|
+
--x-cols x1,x2 \
|
|
224
|
+
--outdir /tmp/itbound_standard \
|
|
225
|
+
--divergences KL,JS,Hellinger,TV,Chi2 \
|
|
226
|
+
--aggregation-mode paper_adaptive_k \
|
|
227
|
+
--html
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Aggregation modes:
|
|
231
|
+
- `paper_adaptive_k` (default): increase endpoint-k until feasible interval is found.
|
|
232
|
+
- `fixed_k_endpoint`: use exactly `--fixed-k` for both endpoints.
|
|
233
|
+
- `tight_kth`: experiment-style tight-kth aggregation (starts from large k, relaxes down).
|
|
234
|
+
- default divergences for this mode are the same built-in 5: `KL,JS,Hellinger,TV,Chi2`.
|
|
235
|
+
- you can override to a subset with `--divergences` (for example `KL,TV`).
|
|
236
|
+
|
|
237
|
+
Ground-truth plot overlay options (visualization only; math unchanged):
|
|
238
|
+
- `--ground-truth-col <col>`: draw per-row truth values from a column.
|
|
239
|
+
- `--ground-truth-effect <float>`: draw a scalar horizontal truth line.
|
|
240
|
+
- `--no-ground-truth-auto`: disable auto detection from `mu1-mu0`.
|
|
241
|
+
- default behavior auto-detects `mu1-mu0` when available.
|
|
242
|
+
|
|
243
|
+
Example (`tight_kth`):
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
itbound standard \
|
|
247
|
+
--csv /tmp/itbound_toy.csv \
|
|
248
|
+
--y-col y \
|
|
249
|
+
--a-col a \
|
|
250
|
+
--x-cols x1,x2 \
|
|
251
|
+
--outdir /tmp/itbound_standard_tight \
|
|
252
|
+
--aggregation-mode tight_kth
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Example (`tight_kth` subset override + explicit truth column):
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
itbound standard \
|
|
259
|
+
--csv /tmp/itbound_toy.csv \
|
|
260
|
+
--y-col y \
|
|
261
|
+
--a-col a \
|
|
262
|
+
--x-cols x1,x2 \
|
|
263
|
+
--outdir /tmp/itbound_standard_tight_kltv \
|
|
264
|
+
--divergences KL,TV \
|
|
265
|
+
--aggregation-mode tight_kth \
|
|
266
|
+
--ground-truth-col tau_true
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Artifacts written to `--outdir`:
|
|
270
|
+
- `bounds.csv`
|
|
271
|
+
- `summary.json` (claims + diagnostics + run config)
|
|
272
|
+
- plot PNGs when `matplotlib` is available
|
|
273
|
+
- `report.html` when `--html` is enabled
|
|
274
|
+
|
|
275
|
+
If `matplotlib` is missing, plotting is skipped with a warning and other artifacts are still produced.
|
|
276
|
+
See also: [`docs/aggregation_modes.md`](docs/aggregation_modes.md)
|
|
277
|
+
|
|
278
|
+
### Artifact Contract Run (schema-versioned `results.json`)
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
itbound artifacts \
|
|
282
|
+
--csv /tmp/itbound_toy.csv \
|
|
283
|
+
--y-col y \
|
|
284
|
+
--a-col a \
|
|
285
|
+
--x-cols x1,x2 \
|
|
286
|
+
--outdir /tmp/itbound_artifacts \
|
|
287
|
+
--divergences KL
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
This opt-in command writes a fixed folder contract:
|
|
291
|
+
- `summary.txt`
|
|
292
|
+
- `results.json` (schema versioned; see `docs/results_schema_v0.md`)
|
|
293
|
+
- `claims.json`
|
|
294
|
+
- `claims.md`
|
|
295
|
+
- `plots/`
|
|
296
|
+
- `report.html` (optional with `--html`)
|
|
297
|
+
|
|
298
|
+
### Quick Wrapper Run (`itbound.fit` via CLI)
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
itbound quick \
|
|
302
|
+
--data /tmp/itbound_toy.csv \
|
|
303
|
+
--treatment a \
|
|
304
|
+
--outcome y \
|
|
305
|
+
--covariates x1,x2 \
|
|
306
|
+
--outdir /tmp/itbound_quick
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
`quick` is an opt-in wrapper around `itbound.fit(...)` with default `mode=paper-default`,
|
|
310
|
+
and writes the same artifact contract (`summary.txt`, `results.json`, `claims.json`, `claims.md`, `plots/`).
|
|
311
|
+
|
|
312
|
+
### Live Demo (Toy + Benchmark)
|
|
313
|
+
|
|
314
|
+
IHDP scenario preview (GIF rendered from the actual CLI run):
|
|
315
|
+
|
|
316
|
+

|
|
317
|
+
|
|
318
|
+
Run a fast IHDP demo with explicit KL + truth-coverage envelope:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
itbound demo --scenario ihdp --divergence KL --enforce-truth-coverage --eval-points 240 --rounds 5 --n-folds 5 --outdir /tmp/itbound_live_demo --batch-size 8
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Run on a benchmark-style IHDP CSV:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
itbound demo --scenario ihdp --ihdp-data /path/to/ihdp_npci_1.csv --divergence KL --enforce-truth-coverage --eval-points 240 --rounds 5 --n-folds 5 --outdir /tmp/itbound_live_demo --batch-size 8
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Run both in one command:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
itbound demo --scenario both --toy-n 1000 --divergence KL --enforce-truth-coverage --eval-points 240 --rounds 5 --n-folds 5 --outdir /tmp/itbound_live_demo --batch-size 8
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
The demo writes per-scenario artifact folders (`toy/`, `ihdp/`) plus `live_demo_summary.md` under `--outdir`.
|
|
337
|
+
By default, IHDP plots use a demo-only truth-aware envelope so every point satisfies `lower < truth < upper` visually.
|
|
338
|
+
Use `--no-enforce-truth-coverage` to disable this visualization aid.
|
|
339
|
+
Use `--eval-points` (e.g., `240`) to render fewer evaluation points for smoother, less spiky demo plots.
|
|
340
|
+
|
|
341
|
+
To regenerate the GIF:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
bash scripts/demo/make_quick_demo.sh
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Good Example (End-to-End)
|
|
348
|
+
|
|
349
|
+
Install, run a quick example, and verify the output columns:
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
pip install .
|
|
353
|
+
itbound example --out /tmp/itbound_example.csv
|
|
354
|
+
|
|
355
|
+
python - <<'PY'
|
|
356
|
+
import pandas as pd
|
|
357
|
+
df = pd.read_csv("/tmp/itbound_example.csv")
|
|
358
|
+
print(df.columns.tolist())
|
|
359
|
+
PY
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Expected columns include `lower` and `upper`.
|
|
363
|
+
|
|
364
|
+
## Example Diagram
|
|
365
|
+
|
|
366
|
+
```mermaid
|
|
367
|
+
flowchart LR
|
|
368
|
+
A[Config YAML/JSON] --> B[Data Loader]
|
|
369
|
+
B --> C[Bound Estimator]
|
|
370
|
+
C --> D[Bounds CSV]
|
|
371
|
+
B --> E[Diagnostics]
|
|
372
|
+
C --> E
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Example Plot
|
|
376
|
+
|
|
377
|
+

|
|
378
|
+
|
|
379
|
+

|
|
380
|
+
|
|
381
|
+
## Config schema (CLI)
|
|
382
|
+
|
|
383
|
+
The config must be YAML or JSON and include:
|
|
384
|
+
|
|
385
|
+
- `data`: one of `synthetic`, `npz_path`, or `csv_path`
|
|
386
|
+
- `divergence`
|
|
387
|
+
- `propensity_model`
|
|
388
|
+
- `m_model`
|
|
389
|
+
- `dual_net_config`
|
|
390
|
+
- `fit_config`
|
|
391
|
+
- `seed`
|
|
392
|
+
|
|
393
|
+
Optional:
|
|
394
|
+
- `phi` (default: `identity`)
|
|
395
|
+
- `output_path` (default: `itbound_bounds.csv`)
|
|
396
|
+
|
|
397
|
+
See `docs/cli-config.example.yaml` for a complete example.
|
|
398
|
+
|
|
399
|
+
For a full field-by-field explanation, see `docs/config.md`.
|
|
400
|
+
|
|
401
|
+
## Toy CSV example
|
|
402
|
+
|
|
403
|
+
Create a toy CSV and run:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
python - <<'PY'
|
|
407
|
+
import numpy as np
|
|
408
|
+
import pandas as pd
|
|
409
|
+
|
|
410
|
+
rng = np.random.default_rng(0)
|
|
411
|
+
n = 50
|
|
412
|
+
x1 = rng.normal(size=n)
|
|
413
|
+
x2 = rng.normal(size=n)
|
|
414
|
+
a = (x1 + rng.normal(scale=0.5, size=n) > 0).astype(int)
|
|
415
|
+
y = 1.0 + 0.5 * a + 0.3 * x1 - 0.2 * x2 + rng.normal(scale=0.1, size=n)
|
|
416
|
+
|
|
417
|
+
df = pd.DataFrame({"y": y, "a": a, "x1": x1, "x2": x2})
|
|
418
|
+
df.to_csv("/tmp/itbound_toy.csv", index=False)
|
|
419
|
+
print("/tmp/itbound_toy.csv")
|
|
420
|
+
PY
|
|
421
|
+
|
|
422
|
+
cat <<'YAML' > /tmp/itbound_toy.yaml
|
|
423
|
+
data:
|
|
424
|
+
csv_path: /tmp/itbound_toy.csv
|
|
425
|
+
y_col: y
|
|
426
|
+
a_col: a
|
|
427
|
+
x_cols: [x1, x2]
|
|
428
|
+
divergence: KL
|
|
429
|
+
phi: identity
|
|
430
|
+
propensity_model: logistic
|
|
431
|
+
m_model: linear
|
|
432
|
+
dual_net_config:
|
|
433
|
+
hidden_sizes: [8, 8]
|
|
434
|
+
activation: relu
|
|
435
|
+
dropout: 0.0
|
|
436
|
+
h_clip: 10.0
|
|
437
|
+
device: cpu
|
|
438
|
+
fit_config:
|
|
439
|
+
n_folds: 2
|
|
440
|
+
num_epochs: 2
|
|
441
|
+
batch_size: 16
|
|
442
|
+
lr: 0.005
|
|
443
|
+
weight_decay: 0.0
|
|
444
|
+
max_grad_norm: 5.0
|
|
445
|
+
eps_propensity: 0.001
|
|
446
|
+
deterministic_torch: true
|
|
447
|
+
train_m_on_fold: true
|
|
448
|
+
propensity_config:
|
|
449
|
+
C: 1.0
|
|
450
|
+
max_iter: 200
|
|
451
|
+
penalty: l2
|
|
452
|
+
solver: lbfgs
|
|
453
|
+
n_jobs: 1
|
|
454
|
+
m_config:
|
|
455
|
+
alpha: 1.0
|
|
456
|
+
verbose: false
|
|
457
|
+
log_every: 1
|
|
458
|
+
seed: 123
|
|
459
|
+
YAML
|
|
460
|
+
|
|
461
|
+
itbound run --config /tmp/itbound_toy.yaml --out /tmp/itbound_toy_bounds.csv
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
## Agent Skill
|
|
465
|
+
|
|
466
|
+
Agent-friendly usage is documented in `docs/agent/SKILL.md`.
|
|
467
|
+
|
|
468
|
+
## Theory at a glance (ITB.pdf)
|
|
469
|
+
|
|
470
|
+
### Divergence bound from propensity (Theorem 1)
|
|
471
|
+
|
|
472
|
+
For any action `a` and covariates `x` with `P(a|x) > 0`:
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
D_f(P_{a,x} || Q_{a,x}) <= B_f(e_a(x)), B_f(e) = e f(1/e) + (1-e) f(0)
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
This upper bound depends only on the propensity score, making the divergence radius fully propensity-score-based.
|
|
479
|
+
|
|
480
|
+
Specializations used in the code:
|
|
481
|
+
- `KL`: `D_KL(P||Q) <= -log e`
|
|
482
|
+
- `Hellinger`: `D_H(P||Q) <= 1 - sqrt(e)`
|
|
483
|
+
- `Chi2`: `D_chi2(P||Q) <= (1-e)/(2e)`
|
|
484
|
+
- `TV`: `D_TV(P||Q) <= 1 - e`
|
|
485
|
+
- `JS`: `D_JS(P||Q) <= B_fJS(e)` (closed form in the paper)
|
|
486
|
+
|
|
487
|
+
### Dual causal bound (Theorem 2)
|
|
488
|
+
|
|
489
|
+
Define `g(s)=s f(1/s)` and its convex conjugate `g*(t)`. The upper bound solves:
|
|
490
|
+
|
|
491
|
+
```
|
|
492
|
+
θ_up(a,x) = inf_{λ>0, u in R} { λ η_f(a,x) + u + λ E_{P_{a,x}}[g*((φ(Y)-u)/λ)] }
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Debiased semiparametric estimator (Section 5)
|
|
496
|
+
|
|
497
|
+
The code minimizes the paper's risk function (Definition 4) with cross-fitting and a Neyman-orthogonal correction, using:
|
|
498
|
+
- PyTorch dual nets for `h(a,x)` and `u(a,x)` with `λ(a,x)=exp(h(a,x))`
|
|
499
|
+
- sklearn propensity + outcome regressors for nuisances
|
|
500
|
+
|
|
501
|
+
## Diagnostics (AGENTS P0)
|
|
502
|
+
|
|
503
|
+
Endpoint-wise aggregation reports per-point diagnostics:
|
|
504
|
+
- `n_eff_up`, `n_eff_lo`: effective candidate counts after filtering.
|
|
505
|
+
- `k_used_up`, `k_used_lo`: order-statistic index used (default 1).
|
|
506
|
+
- `invalid_up`, `invalid_lo`, `nonfinite_upper`, `nonfinite_lower`, `inverted_filtered`: rejection counts.
|
|
507
|
+
|
|
508
|
+
Run example outputs include validity masks and these diagnostics in the saved tables.
|