tabdgp 0.0.1__tar.gz → 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.
- {tabdgp-0.0.1 → tabdgp-0.2.0}/.github/workflows/ci.yml +7 -3
- tabdgp-0.2.0/.github/workflows/release.yml +50 -0
- tabdgp-0.2.0/.gitignore +23 -0
- tabdgp-0.2.0/CITATION.cff +11 -0
- tabdgp-0.2.0/CONTEXT.md +179 -0
- {tabdgp-0.0.1 → tabdgp-0.2.0}/CONTRIBUTING.md +4 -6
- tabdgp-0.2.0/PKG-INFO +105 -0
- tabdgp-0.2.0/README.md +84 -0
- {tabdgp-0.0.1 → tabdgp-0.2.0}/docs/adr/0001-one-dataset-per-draw-keyed-in-numpy.md +29 -14
- tabdgp-0.2.0/docs/adr/0002-package-release-first-paper-conditional.md +67 -0
- tabdgp-0.2.0/docs/adr/0003-grouping-factors-as-units-in-the-graph.md +121 -0
- tabdgp-0.2.0/docs/adr/0004-the-sizes-are-the-envelope.md +79 -0
- tabdgp-0.2.0/docs/conventions.md +230 -0
- {tabdgp-0.0.1 → tabdgp-0.2.0}/pyproject.toml +18 -6
- tabdgp-0.2.0/src/tabdgp/__init__.py +24 -0
- tabdgp-0.2.0/src/tabdgp/column.py +271 -0
- tabdgp-0.2.0/src/tabdgp/draw.py +107 -0
- tabdgp-0.2.0/src/tabdgp/graph.py +267 -0
- tabdgp-0.2.0/src/tabdgp/hyperprior.py +409 -0
- tabdgp-0.2.0/src/tabdgp/mechanism.py +165 -0
- tabdgp-0.2.0/tests/fixtures/build.py +104 -0
- tabdgp-0.2.0/tests/test_citation.py +17 -0
- tabdgp-0.2.0/tests/test_column.py +653 -0
- tabdgp-0.2.0/tests/test_draw.py +437 -0
- tabdgp-0.2.0/tests/test_graph.py +620 -0
- tabdgp-0.2.0/tests/test_hyperprior.py +454 -0
- tabdgp-0.2.0/tests/test_mechanism.py +440 -0
- tabdgp-0.2.0/tests/test_readme.py +31 -0
- tabdgp-0.2.0/uv.lock +936 -0
- tabdgp-0.0.1/.gitignore +0 -12
- tabdgp-0.0.1/CONTEXT.md +0 -99
- tabdgp-0.0.1/PKG-INFO +0 -76
- tabdgp-0.0.1/README.md +0 -58
- tabdgp-0.0.1/ROADMAP.md +0 -19
- tabdgp-0.0.1/docs/conventions.md +0 -164
- tabdgp-0.0.1/docs/prior-art.md +0 -65
- tabdgp-0.0.1/lab/README.md +0 -7
- tabdgp-0.0.1/src/tabdgp/__init__.py +0 -3
- tabdgp-0.0.1/tests/test_readme.py +0 -14
- tabdgp-0.0.1/uv.lock +0 -181
- {tabdgp-0.0.1 → tabdgp-0.2.0}/LICENSE +0 -0
- {tabdgp-0.0.1 → tabdgp-0.2.0}/docs/adr/.gitkeep +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
# Format
|
|
2
|
-
# on the
|
|
1
|
+
# Format and lint checks and the fast tests,
|
|
2
|
+
# on three operating systems and on the oldest and newest supported Python;
|
|
3
|
+
# the slow proofs run by hand or on the cluster (`uv run pytest -m slow`).
|
|
3
4
|
name: CI
|
|
4
5
|
|
|
5
6
|
on:
|
|
@@ -13,12 +14,15 @@ jobs:
|
|
|
13
14
|
fail-fast: false
|
|
14
15
|
matrix:
|
|
15
16
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
17
|
+
python: ['3.12', '3.14']
|
|
18
|
+
name: ${{ matrix.os }}, Python ${{ matrix.python }}
|
|
16
19
|
runs-on: ${{ matrix.os }}
|
|
17
20
|
steps:
|
|
18
21
|
- uses: actions/checkout@v7
|
|
19
22
|
- uses: astral-sh/setup-uv@v10.2.0 # setup-uv publishes no major tag
|
|
20
23
|
with:
|
|
21
|
-
python-version:
|
|
24
|
+
python-version: ${{ matrix.python }}
|
|
22
25
|
- run: uv sync
|
|
23
26
|
- run: uv run ruff format --check .
|
|
27
|
+
- run: uv run ruff check .
|
|
24
28
|
- run: uv run pytest -rs
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# The release to PyPI by trusted publishing: a published GitHub release uploads its sdist and
|
|
2
|
+
# wheel to PyPI; a manual run uploads them to TestPyPI instead, as the dry run. Zenodo
|
|
3
|
+
# archives the same release event on its own.
|
|
4
|
+
name: Release
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
# the build runs without the publishing token
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
- uses: astral-sh/setup-uv@v10.2.0 # setup-uv publishes no major tag
|
|
18
|
+
# PyPI never takes a version twice, so a tag that names another version stops here
|
|
19
|
+
- if: github.event_name == 'release'
|
|
20
|
+
env:
|
|
21
|
+
TAG: ${{ github.event.release.tag_name }}
|
|
22
|
+
run: |
|
|
23
|
+
expected="v$(uv version --short)"
|
|
24
|
+
if [ "$TAG" != "$expected" ]; then
|
|
25
|
+
echo "::error::the tag $TAG does not name the package version $expected"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
- run: uv build
|
|
29
|
+
- uses: actions/upload-artifact@v7
|
|
30
|
+
with:
|
|
31
|
+
name: dist
|
|
32
|
+
path: dist/
|
|
33
|
+
|
|
34
|
+
publish:
|
|
35
|
+
needs: build
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
environment: pypi
|
|
38
|
+
permissions:
|
|
39
|
+
id-token: write # the OIDC token PyPI exchanges for a short-lived upload token
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/download-artifact@v8
|
|
42
|
+
with:
|
|
43
|
+
name: dist
|
|
44
|
+
path: dist/
|
|
45
|
+
- if: github.event_name == 'release'
|
|
46
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
47
|
+
- if: github.event_name == 'workflow_dispatch'
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
49
|
+
with:
|
|
50
|
+
repository-url: https://test.pypi.org/legacy/
|
tabdgp-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
dist/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.hypothesis/
|
|
8
|
+
.ruff_cache/
|
|
9
|
+
.ipynb_checkpoints/
|
|
10
|
+
.DS_Store
|
|
11
|
+
.claude/
|
|
12
|
+
# local agent instructions (docs/conventions.md is the public part) and the roadmap
|
|
13
|
+
CLAUDE.md
|
|
14
|
+
ROADMAP.md
|
|
15
|
+
next.md
|
|
16
|
+
# design notes kept local: the lab notes and the prior-art survey
|
|
17
|
+
lab/
|
|
18
|
+
docs/prior-art.md
|
|
19
|
+
docs/scamd-audit.md
|
|
20
|
+
docs/related-simulators.md
|
|
21
|
+
docs/frontier-priors.md
|
|
22
|
+
# the model reports the survey read, kept local for their licences
|
|
23
|
+
docs/reports/
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: If you use TabDGP, please cite it as below.
|
|
3
|
+
title: 'TabDGP: a data-generating process for grouped and flat tables'
|
|
4
|
+
authors:
|
|
5
|
+
- family-names: Kipnis
|
|
6
|
+
given-names: Alex
|
|
7
|
+
repository-code: https://github.com/adkipnis/tabdgp
|
|
8
|
+
license: MIT
|
|
9
|
+
version: 0.2.0
|
|
10
|
+
date-released: 2026-10-14
|
|
11
|
+
doi: 10.5281/zenodo.23322845
|
tabdgp-0.2.0/CONTEXT.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# TabDGP
|
|
2
|
+
|
|
3
|
+
A data-generating process for grouped and flat tables: what is drawn, how, and from which
|
|
4
|
+
distributions. The covariate terms are those of metabeta's generalized linear mixed
|
|
5
|
+
model (GLMM) glossary (`packages/mixed/CONTEXT.md` of metabeta-v3, a private repository),
|
|
6
|
+
restated here in its words and adapted where TabDGP differs; statistical terms (grouping
|
|
7
|
+
factor, family, link) are not redefined.
|
|
8
|
+
|
|
9
|
+
## Language
|
|
10
|
+
|
|
11
|
+
### Covariates
|
|
12
|
+
|
|
13
|
+
**Covariate generator**:
|
|
14
|
+
The process that draws a dataset's grouping structure and its typed covariate columns,
|
|
15
|
+
continuous, binary, categorical or ordered, each within-group or group-level, with the quirks
|
|
16
|
+
of real tables. TabDGP is one; it draws an outcome only as the optional outcome node.
|
|
17
|
+
_Avoid_: predictor simulation, feature matrix, X generator, design-matrix generator
|
|
18
|
+
|
|
19
|
+
**Design matrix**:
|
|
20
|
+
The coding of the covariates the linear predictor sees: an intercept column, z-scored
|
|
21
|
+
continuous columns, 0/1 binary columns, K − 1 treatment-coded columns per categorical.
|
|
22
|
+
Derived from the covariates, never drawn; the hyperprior's design-column budget counts its
|
|
23
|
+
columns besides the intercept.
|
|
24
|
+
_Avoid_: X for the uncoded covariates, features
|
|
25
|
+
|
|
26
|
+
**Within-group covariate** / **group-level covariate**:
|
|
27
|
+
A covariate that varies within the groups of a factor, versus one constant within each group
|
|
28
|
+
of some factor (a school's size, a person's sex). A within-group covariate whose mean differs
|
|
29
|
+
between groups is **group-confounded**.
|
|
30
|
+
_Avoid_: level-1 and level-2 variable, cluster-level, contextual variable
|
|
31
|
+
|
|
32
|
+
**Group share**:
|
|
33
|
+
How much of a within-group node's variance comes from its group part, one value per group of
|
|
34
|
+
one grouping factor, rather than its row part, one value per row: the strength of its group
|
|
35
|
+
confounding. The between-group share measured on its values can be larger, since its row part
|
|
36
|
+
may read group-confounded parents.
|
|
37
|
+
_Avoid_: ICC unqualified (the fitter's, on the outcome), between-group share (what the
|
|
38
|
+
measurement pass records), random-intercept variance
|
|
39
|
+
|
|
40
|
+
**Quirk**:
|
|
41
|
+
A property of real tables that an independent and identically distributed (i.i.d.) simulator
|
|
42
|
+
lacks and on which an amortized posterior goes wrong: group confounding, empty cells, rare
|
|
43
|
+
levels, ties, bounds, irregular time, near dependence, leverage points.
|
|
44
|
+
_Avoid_: edge case, noise, messiness
|
|
45
|
+
|
|
46
|
+
### The graph
|
|
47
|
+
|
|
48
|
+
**Node**:
|
|
49
|
+
One variable of a dataset's structural causal model (SCM): a grouping factor, a group-level or
|
|
50
|
+
within-group covariate, time, treatment, or the outcome node. A node has a parent set and a
|
|
51
|
+
mechanism; a node without parents is a root.
|
|
52
|
+
_Avoid_: feature, variable unqualified, neuron (of an MLP)
|
|
53
|
+
|
|
54
|
+
**Grouping factor**:
|
|
55
|
+
A root node whose values assign every row to one of its G groups, in metabeta's words "a
|
|
56
|
+
categorical variable whose levels index random effects"; a dataset has none (a flat table),
|
|
57
|
+
one or several. Two grouping factors are **crossed** when their groups combine freely and
|
|
58
|
+
**nested** when each group of the subordinate one lies within one group of the superior one,
|
|
59
|
+
which has fewer groups.
|
|
60
|
+
_Avoid_: factor alone (a categorical column), cluster, subject (one kind of grouping factor),
|
|
61
|
+
random-effects term
|
|
62
|
+
|
|
63
|
+
**Superior** / **subordinate**:
|
|
64
|
+
A grouping factor is superior to one nested in it, whose groups lie within its own; the nested
|
|
65
|
+
one is subordinate. The row is subordinate to every factor.
|
|
66
|
+
_Avoid_: coarser and finer, parent and child (the graph's edges), higher and lower level
|
|
67
|
+
|
|
68
|
+
**Unit**:
|
|
69
|
+
What a node is drawn once per: the row, or one grouping factor, in which case the node takes
|
|
70
|
+
one value per group of that factor, repeated across the group's rows (broadcast). A column at
|
|
71
|
+
the row unit is a within-group covariate; one at a grouping factor's unit is group-level. A
|
|
72
|
+
nested grouping factor is a unit subordinate to the one it nests in; crossed ones are units
|
|
73
|
+
without an order between them.
|
|
74
|
+
_Avoid_: level (a factor level, or the multilevel literature's level 1 and 2), hierarchy
|
|
75
|
+
level, grain, scope
|
|
76
|
+
|
|
77
|
+
**Mechanism**:
|
|
78
|
+
The function that computes a node's values from its parents' values and its own noise, drawn
|
|
79
|
+
per node from a mechanism family (linear, a small MLP, a tree). A root's mechanism is its noise.
|
|
80
|
+
_Avoid_: layer, activation (one part of it), edge function
|
|
81
|
+
|
|
82
|
+
**Generating graph**:
|
|
83
|
+
The directed acyclic graph of a dataset's nodes and their parent sets, returned with every
|
|
84
|
+
dataset.
|
|
85
|
+
_Avoid_: causal graph unqualified, DAG (one property of it), architecture
|
|
86
|
+
|
|
87
|
+
**Latent node**:
|
|
88
|
+
A node of the generating graph that is not a column of the table, kept in the output so that
|
|
89
|
+
the dataset stays white-box.
|
|
90
|
+
_Avoid_: hidden unit, confounder (a role a latent node can play)
|
|
91
|
+
|
|
92
|
+
**Column**:
|
|
93
|
+
A node observed in the table, with its metadata: type (continuous, binary, categorical,
|
|
94
|
+
ordered), levels, role (grouping factor, covariate, time, treatment, outcome), and the
|
|
95
|
+
parameters its values were drawn with.
|
|
96
|
+
_Avoid_: feature, variable unqualified
|
|
97
|
+
|
|
98
|
+
**Factor level**:
|
|
99
|
+
One of the K categories of a binary, categorical or ordered column, or one group of a
|
|
100
|
+
grouping factor; R's `levels()`.
|
|
101
|
+
_Avoid_: level unqualified, category, class
|
|
102
|
+
|
|
103
|
+
**Marginal**:
|
|
104
|
+
The distribution a continuous column's values are mapped onto after the SCM, from a catalogue
|
|
105
|
+
of families (skewed, heavy-tailed, bounded, zero-inflated), keeping their ranks.
|
|
106
|
+
_Avoid_: noise distribution (the root's), prior
|
|
107
|
+
|
|
108
|
+
**Post-hoc type**:
|
|
109
|
+
The column type a continuous node is turned into after the SCM, by thresholds or bins on its
|
|
110
|
+
values: binary, categorical, ordered.
|
|
111
|
+
_Avoid_: dtype, encoding (the design matrix's)
|
|
112
|
+
|
|
113
|
+
### The draw
|
|
114
|
+
|
|
115
|
+
**Draw**:
|
|
116
|
+
The one public call: given a key and a hyperprior, one dataset, a pure function of both. Who
|
|
117
|
+
draws many loops over indices.
|
|
118
|
+
_Avoid_: sample (a row or a value), generate, batch
|
|
119
|
+
|
|
120
|
+
**Key**:
|
|
121
|
+
A seed and an index, the identity of one dataset: the same key, hyperprior and versions of
|
|
122
|
+
TabDGP and numpy give the same dataset bitwise, whatever the batch, worker or shard it is
|
|
123
|
+
drawn in.
|
|
124
|
+
_Avoid_: rng, random state, seed alone
|
|
125
|
+
|
|
126
|
+
**Dataset**:
|
|
127
|
+
What a draw returns: the columns as named arrays in their natural dtype, their metadata, the
|
|
128
|
+
generating graph, the latent nodes' values, the hyperparameters every field resolved to except
|
|
129
|
+
those each column or node draws for itself, and the key. Never padded, never a file.
|
|
130
|
+
_Avoid_: batch, table (the columns alone), sample, corpus (the consumer's set of keys)
|
|
131
|
+
|
|
132
|
+
**Hyperprior**:
|
|
133
|
+
The one config of distributions from which every quantity of a dataset is drawn: sizes,
|
|
134
|
+
graph, mechanisms, marginals, types, quirks, reached through a preset. The grouped preset's
|
|
135
|
+
defaults are to be matched to mixedbench's registry and then widened; they are what the
|
|
136
|
+
proofs certify.
|
|
137
|
+
_Avoid_: prior (the fitter's, over parameters), config unqualified, meta-distribution
|
|
138
|
+
|
|
139
|
+
**Preset**:
|
|
140
|
+
A named hyperprior for one kind of table, grouped or flat today, item response, survival or
|
|
141
|
+
causal later: a choice of fields, never a new mechanism. Every draw starts from one; metabeta
|
|
142
|
+
draws from the grouped preset.
|
|
143
|
+
_Avoid_: dataset type, kind, mode
|
|
144
|
+
|
|
145
|
+
**Override**:
|
|
146
|
+
A point value or a distribution passed for one field of a preset, replacing its default for
|
|
147
|
+
that call. Neither a standalone user nor metabeta passes one by default; an override serves a
|
|
148
|
+
study, an ablation or a size outside the preset.
|
|
149
|
+
_Avoid_: setting, parameter, hyperparameter
|
|
150
|
+
|
|
151
|
+
**Quirk axis**:
|
|
152
|
+
One field of the hyperprior that controls one quirk of the catalogue, granted only when
|
|
153
|
+
mixedbench's measurement pass shows that real tables have the quirk strongly enough.
|
|
154
|
+
_Avoid_: noise, perturbation, augmentation
|
|
155
|
+
|
|
156
|
+
**Outcome node**:
|
|
157
|
+
An optional node whose parents are drawn from the covariates, with a family, a link, the
|
|
158
|
+
random effects per grouping factor and terms a GLMM lacks, that builds white-box
|
|
159
|
+
misspecified datasets. Just another node; never drawn unless asked for.
|
|
160
|
+
_Avoid_: y, target, label, response unqualified
|
|
161
|
+
|
|
162
|
+
**Random effect**:
|
|
163
|
+
A per-group parameter of the outcome, an intercept or a slope, drawn jointly per group of a
|
|
164
|
+
grouping factor in metabeta's parameterisation; metabeta's term. Only the outcome node draws
|
|
165
|
+
random effects; a group-level node, latent or observed, is covariate structure, which a GLMM
|
|
166
|
+
takes as given.
|
|
167
|
+
_Avoid_: group effect, random intercept for a latent group-level node
|
|
168
|
+
|
|
169
|
+
### The proofs
|
|
170
|
+
|
|
171
|
+
**Two-sample test**:
|
|
172
|
+
A classifier two-sample test (C2ST) on the summary vector of generated and registry tables:
|
|
173
|
+
the defaults pass when its accuracy stays below the bar.
|
|
174
|
+
_Avoid_: discriminator, realism score
|
|
175
|
+
|
|
176
|
+
**Containment test**:
|
|
177
|
+
The test that every registry row's summary vector lies inside the support of the generated
|
|
178
|
+
ones.
|
|
179
|
+
_Avoid_: coverage (the fitter's credible-interval property)
|
|
@@ -24,7 +24,7 @@ git clone https://github.com/adkipnis/tabdgp
|
|
|
24
24
|
cd tabdgp
|
|
25
25
|
uv sync
|
|
26
26
|
uv run pytest # the fast tests
|
|
27
|
-
uv run pytest -m slow # the proofs against mixedbench's registry
|
|
27
|
+
uv run pytest -m slow # the proofs against mixedbench's registry, from roadmap item 3
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
## Find your way
|
|
@@ -33,13 +33,11 @@ uv run pytest -m slow # the proofs against mixedbench's registry
|
|
|
33
33
|
src/tabdgp/ the package; each module's docstring says what it defines and how
|
|
34
34
|
tests/ mirrors src/, fixtures beside the tests
|
|
35
35
|
docs/adr/ the design decisions and why they were taken
|
|
36
|
-
docs/ the conventions and the proofs' method
|
|
37
|
-
lab/ one notebook per small design choice, indexed in lab/README.md
|
|
38
|
-
examples/ the demo notebook
|
|
36
|
+
docs/ the conventions, and from roadmap item 3 the proofs' method
|
|
39
37
|
```
|
|
40
38
|
|
|
41
39
|
[`CONTEXT.md`](CONTEXT.md) defines the words (node, mechanism, hyperprior, override, quirk
|
|
42
|
-
axis, outcome node)
|
|
40
|
+
axis, outcome node) and the covariate terms it shares with metabeta's glossary.
|
|
43
41
|
|
|
44
42
|
## Pull requests
|
|
45
43
|
|
|
@@ -52,7 +50,7 @@ Three rules keep the generator trustworthy:
|
|
|
52
50
|
|
|
53
51
|
- **The defaults are what the proofs certify.** A change to a default distribution of the
|
|
54
52
|
hyperprior, to a proof's seed or to its bar is discussed in an issue first and recorded in
|
|
55
|
-
the
|
|
53
|
+
the release notes; downstream training corpora depend on them.
|
|
56
54
|
- **Written from scratch.** scamd and TabICL's prior are read for ideas; no code is copied
|
|
57
55
|
from either. A mechanism they inspired says so in a comment.
|
|
58
56
|
- **Nothing from downstream.** TabDGP imports nothing from metabeta or mixedbench; the proofs
|
tabdgp-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tabdgp
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A data-generating process for grouped and flat tables, to be matched to a registry of real tables
|
|
5
|
+
Project-URL: Repository, https://github.com/adkipnis/tabdgp
|
|
6
|
+
Project-URL: Issues, https://github.com/adkipnis/tabdgp/issues
|
|
7
|
+
Author-email: Alex Kipnis <adkipnis@users.noreply.github.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: numpy<3,>=2.3
|
|
19
|
+
Requires-Dist: pydantic<3,>=2.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
[](https://github.com/adkipnis/tabdgp/actions/workflows/ci.yml)
|
|
23
|
+
[](https://pypi.org/project/tabdgp/)
|
|
24
|
+
[](https://github.com/adkipnis/tabdgp/blob/main/pyproject.toml)
|
|
25
|
+
[](https://github.com/adkipnis/tabdgp/blob/main/LICENSE)
|
|
26
|
+
[](https://doi.org/10.5281/zenodo.23322845)
|
|
27
|
+
|
|
28
|
+
# TabDGP
|
|
29
|
+
|
|
30
|
+
A data-generating process (DGP) for grouped and flat tables.
|
|
31
|
+
|
|
32
|
+
TabDGP simulates tabular datasets from a random structural causal model (SCM) and aims to
|
|
33
|
+
reproduce the quirks of real data. Each table comes with the graph and the settings that
|
|
34
|
+
generated it.
|
|
35
|
+
|
|
36
|
+
> **Alpha.** Release 0.2 draws grouped and flat tables from defaults that are round guesses;
|
|
37
|
+
> the rest is planned below. Before 1.0, a release may change the dataset a key draws.
|
|
38
|
+
|
|
39
|
+
## Highlights
|
|
40
|
+
|
|
41
|
+
- **Grouped or flat.** One to three grouping factors by default, nested or crossed, with 2 to
|
|
42
|
+
400 groups each. A covariate varies by row or is constant within the groups of one factor.
|
|
43
|
+
`Hyperprior.flat()` draws none.
|
|
44
|
+
- **White-box.** Each dataset carries its graph, latent nodes, column metadata and hyperparameters.
|
|
45
|
+
- **Reproducible.** A dataset is a pure function of its key (a seed and an index) and the
|
|
46
|
+
hyperprior, whatever batch or worker draws it.
|
|
47
|
+
- **Overridable.** Replace any default distribution by a point value or another distribution.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
pip install tabdgp
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quickstart
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from tabdgp import Hyperprior, draw
|
|
59
|
+
|
|
60
|
+
hyperprior = Hyperprior.grouped(rows=100, design_columns=5) # two overrides on the grouped preset
|
|
61
|
+
dataset = draw(seed=0, index=0, hyperprior=hyperprior) # the key: a seed and an index
|
|
62
|
+
unit = dict(zip(dataset.graph.names, dataset.graph.unit)) # per row, or per group of a factor
|
|
63
|
+
for name, column in dataset.metadata.items():
|
|
64
|
+
print(name, column.type, unit[name], dataset.columns[name][:3].round(2))
|
|
65
|
+
print(len(dataset.latent), 'latent nodes,', dataset.graph.parents.sum(), 'edges')
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
g0 categorical g0 [4 5 2]
|
|
70
|
+
g1 categorical g1 [ 6 22 29]
|
|
71
|
+
g2 categorical g2 [7 7 5]
|
|
72
|
+
x0 binary g0 [1 1 1]
|
|
73
|
+
x1 binary row [1 1 1]
|
|
74
|
+
x2 continuous row [0.36 0.69 0.15]
|
|
75
|
+
x3 binary row [0 0 0]
|
|
76
|
+
x4 binary row [0 1 0]
|
|
77
|
+
7 latent nodes, 16 edges
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Planned
|
|
81
|
+
|
|
82
|
+
- **Quirk axes:** group confounding, rare levels, ties, bounds, near dependence and more.
|
|
83
|
+
- **Matched defaults**, fitted to and checked against
|
|
84
|
+
[mixedbench](https://github.com/adkipnis/mixedbench)'s real grouped tables, then widened.
|
|
85
|
+
- **An outcome node**, optional, for white-box misspecified datasets, with within-group time and
|
|
86
|
+
a binary treatment.
|
|
87
|
+
|
|
88
|
+
## Learn more
|
|
89
|
+
|
|
90
|
+
[`CONTEXT.md`](https://github.com/adkipnis/tabdgp/blob/main/CONTEXT.md) defines the vocabulary.
|
|
91
|
+
|
|
92
|
+
## Contributing
|
|
93
|
+
|
|
94
|
+
Issues and pull requests are welcome; see
|
|
95
|
+
[`CONTRIBUTING.md`](https://github.com/adkipnis/tabdgp/blob/main/CONTRIBUTING.md).
|
|
96
|
+
|
|
97
|
+
## Citing
|
|
98
|
+
|
|
99
|
+
Please cite the release you used, from
|
|
100
|
+
[`CITATION.cff`](https://github.com/adkipnis/tabdgp/blob/main/CITATION.cff) or GitHub's "Cite
|
|
101
|
+
this repository".
|
|
102
|
+
|
|
103
|
+
## Licence
|
|
104
|
+
|
|
105
|
+
[MIT](https://github.com/adkipnis/tabdgp/blob/main/LICENSE).
|
tabdgp-0.2.0/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
[](https://github.com/adkipnis/tabdgp/actions/workflows/ci.yml)
|
|
2
|
+
[](https://pypi.org/project/tabdgp/)
|
|
3
|
+
[](https://github.com/adkipnis/tabdgp/blob/main/pyproject.toml)
|
|
4
|
+
[](https://github.com/adkipnis/tabdgp/blob/main/LICENSE)
|
|
5
|
+
[](https://doi.org/10.5281/zenodo.23322845)
|
|
6
|
+
|
|
7
|
+
# TabDGP
|
|
8
|
+
|
|
9
|
+
A data-generating process (DGP) for grouped and flat tables.
|
|
10
|
+
|
|
11
|
+
TabDGP simulates tabular datasets from a random structural causal model (SCM) and aims to
|
|
12
|
+
reproduce the quirks of real data. Each table comes with the graph and the settings that
|
|
13
|
+
generated it.
|
|
14
|
+
|
|
15
|
+
> **Alpha.** Release 0.2 draws grouped and flat tables from defaults that are round guesses;
|
|
16
|
+
> the rest is planned below. Before 1.0, a release may change the dataset a key draws.
|
|
17
|
+
|
|
18
|
+
## Highlights
|
|
19
|
+
|
|
20
|
+
- **Grouped or flat.** One to three grouping factors by default, nested or crossed, with 2 to
|
|
21
|
+
400 groups each. A covariate varies by row or is constant within the groups of one factor.
|
|
22
|
+
`Hyperprior.flat()` draws none.
|
|
23
|
+
- **White-box.** Each dataset carries its graph, latent nodes, column metadata and hyperparameters.
|
|
24
|
+
- **Reproducible.** A dataset is a pure function of its key (a seed and an index) and the
|
|
25
|
+
hyperprior, whatever batch or worker draws it.
|
|
26
|
+
- **Overridable.** Replace any default distribution by a point value or another distribution.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
pip install tabdgp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quickstart
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from tabdgp import Hyperprior, draw
|
|
38
|
+
|
|
39
|
+
hyperprior = Hyperprior.grouped(rows=100, design_columns=5) # two overrides on the grouped preset
|
|
40
|
+
dataset = draw(seed=0, index=0, hyperprior=hyperprior) # the key: a seed and an index
|
|
41
|
+
unit = dict(zip(dataset.graph.names, dataset.graph.unit)) # per row, or per group of a factor
|
|
42
|
+
for name, column in dataset.metadata.items():
|
|
43
|
+
print(name, column.type, unit[name], dataset.columns[name][:3].round(2))
|
|
44
|
+
print(len(dataset.latent), 'latent nodes,', dataset.graph.parents.sum(), 'edges')
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
g0 categorical g0 [4 5 2]
|
|
49
|
+
g1 categorical g1 [ 6 22 29]
|
|
50
|
+
g2 categorical g2 [7 7 5]
|
|
51
|
+
x0 binary g0 [1 1 1]
|
|
52
|
+
x1 binary row [1 1 1]
|
|
53
|
+
x2 continuous row [0.36 0.69 0.15]
|
|
54
|
+
x3 binary row [0 0 0]
|
|
55
|
+
x4 binary row [0 1 0]
|
|
56
|
+
7 latent nodes, 16 edges
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Planned
|
|
60
|
+
|
|
61
|
+
- **Quirk axes:** group confounding, rare levels, ties, bounds, near dependence and more.
|
|
62
|
+
- **Matched defaults**, fitted to and checked against
|
|
63
|
+
[mixedbench](https://github.com/adkipnis/mixedbench)'s real grouped tables, then widened.
|
|
64
|
+
- **An outcome node**, optional, for white-box misspecified datasets, with within-group time and
|
|
65
|
+
a binary treatment.
|
|
66
|
+
|
|
67
|
+
## Learn more
|
|
68
|
+
|
|
69
|
+
[`CONTEXT.md`](https://github.com/adkipnis/tabdgp/blob/main/CONTEXT.md) defines the vocabulary.
|
|
70
|
+
|
|
71
|
+
## Contributing
|
|
72
|
+
|
|
73
|
+
Issues and pull requests are welcome; see
|
|
74
|
+
[`CONTRIBUTING.md`](https://github.com/adkipnis/tabdgp/blob/main/CONTRIBUTING.md).
|
|
75
|
+
|
|
76
|
+
## Citing
|
|
77
|
+
|
|
78
|
+
Please cite the release you used, from
|
|
79
|
+
[`CITATION.cff`](https://github.com/adkipnis/tabdgp/blob/main/CITATION.cff) or GitHub's "Cite
|
|
80
|
+
this repository".
|
|
81
|
+
|
|
82
|
+
## Licence
|
|
83
|
+
|
|
84
|
+
[MIT](https://github.com/adkipnis/tabdgp/blob/main/LICENSE).
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
status: accepted
|
|
3
3
|
date: 2026-10-11
|
|
4
|
+
amended: 2026-10-11, after the throughput lab note; 2026-10-12, after the column-pooling lab note (#16); 2026-10-12, numpy's version recorded beside TabDGP's; 2026-10-14, ADR 0004: metabeta passes no sizes, `draw` takes a preset and has no default
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# 0001 — One dataset per draw, keyed by seed and index, in numpy
|
|
7
8
|
|
|
8
|
-
TabDGP's first consumer, `metabeta.mixed
|
|
9
|
-
and columns all vary; its roadmap puts padding,
|
|
10
|
-
`metabeta.core`, and its Simulator adds the outcome
|
|
11
|
-
|
|
9
|
+
TabDGP's first consumer, `metabeta.mixed` in the private repository metabeta-v3, trains on
|
|
10
|
+
simulated datasets whose sizes, groups and columns all vary; its roadmap puts padding,
|
|
11
|
+
masking, collate and the `.npz` corpus on `metabeta.core`, and its Simulator adds the outcome
|
|
12
|
+
before anything is written. Grilled on
|
|
13
|
+
2026-10-11 (storage, batch layout, tensor library, roadmap item 1), the decision is:
|
|
12
14
|
**the seed is the corpus.** Dataset `i` is a pure function of its key `(seed, index)`, the
|
|
13
|
-
hyperprior with its overrides and the installed
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
hyperprior with its overrides and the installed versions of TabDGP and numpy, whose generator
|
|
16
|
+
promises no stable streams across its releases; the dataset records both. The public call
|
|
17
|
+
draws one dataset, `draw(seed, index, hyperprior) -> Dataset`, in numpy, at the dataset's own
|
|
18
|
+
shapes. TabDGP never pads, never batches across datasets and never writes a file.
|
|
16
19
|
|
|
17
20
|
## Considered options
|
|
18
21
|
|
|
@@ -55,7 +58,8 @@ TabDGP never pads, never batches across datasets and never writes a file.
|
|
|
55
58
|
group indices as floats, and both consumers derive what they need from the metadata anyway.
|
|
56
59
|
`Dataset` holds the columns as named one-dimensional arrays in their natural dtype, the
|
|
57
60
|
column metadata, the generating graph with every node including the latent ones, the latent
|
|
58
|
-
nodes' values, the hyperparameters every field resolved to, and the key.
|
|
61
|
+
nodes' values, the hyperparameters every field resolved to, and the key. A field each column
|
|
62
|
+
or node draws for itself is recorded with that column or in the graph instead (#16).
|
|
59
63
|
|
|
60
64
|
## Consequences
|
|
61
65
|
|
|
@@ -66,12 +70,23 @@ TabDGP never pads, never batches across datasets and never writes a file.
|
|
|
66
70
|
- The end-to-end test draws dataset `i` alone and inside two different index sets and asserts
|
|
67
71
|
bitwise equality; the proofs draw their fixed-seed datasets by index and store nothing.
|
|
68
72
|
- The hyperprior and its resolution share one Pydantic type: an override is a point value or
|
|
69
|
-
a distribution on a field, a resolved hyperparameter a point value on the same field.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
a distribution on a field, a resolved hyperparameter a point value on the same field. A
|
|
74
|
+
field each column or node draws for itself keeps its override there, and the column
|
|
75
|
+
metadata and the graph record the values drawn (#16).
|
|
76
|
+
- Throughput is a bar, not a hope: a node's CPU workers draw datasets at least as fast as its
|
|
77
|
+
GPU trains on them. For metabeta (4 to 8 cores and one GPU per node, epochs of 4,192
|
|
78
|
+
datasets in minibatches of 16 to 64) that is at least 1,000 datasets per second on 4
|
|
79
|
+
workers at the mean v1 size, about 1 ms per dataset. The unpublished throughput lab note
|
|
80
|
+
(`lab/2026-10-11-throughput/`) measured about 250 per second per core in float32 on an M3,
|
|
81
|
+
so numpy holds; the draw is bound by arithmetic, not by the interpreter, so a padded torch
|
|
82
|
+
batch on CPU buys nothing and one on the node's only GPU takes time from training. The
|
|
83
|
+
bar was first set at 500 per core, before the consumer's numbers were known.
|
|
84
|
+
- Continuous columns and latent values are float32, the precision the network trains in, so
|
|
85
|
+
`torch.from_numpy` hands them over unconverted; single precision also runs the
|
|
86
|
+
activations three to four times faster.
|
|
87
|
+
- When online drawing falls behind, or several models (4 to 16) train at once, a consumer
|
|
88
|
+
draws a corpus once, stores it and lets every run read it, dividing the cost; storage
|
|
89
|
+
stays the consumer's, TabDGP still writes no file.
|
|
75
90
|
- A DataFrame is `pandas.DataFrame(dataset.columns)` and needs no dependency here.
|
|
76
91
|
- For `metabeta.mixed`'s slice A1: generate per epoch from `(seed, index)` in dataloader
|
|
77
92
|
workers, pin TabDGP, snapshot validation and test sets, draw an epoch's sizes first (its
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
status: accepted
|
|
3
|
+
date: 2026-10-11
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0002 — Package release first; a paper only with a finding of its own
|
|
7
|
+
|
|
8
|
+
Three papers already come out of the project TabDGP serves: mixedbench's (registry census,
|
|
9
|
+
contract, suite, opponent lines; NeurIPS Datasets & Benchmarks 2027), mixedsurvey's (the GLMM
|
|
10
|
+
practice survey) and later metabeta's (amortized inference). Asked on 2026-10-11 whether TabDGP
|
|
11
|
+
earns a fourth once item 5 or 6 is reached, the decision is: **a proper package release and a
|
|
12
|
+
JOSS paper as a citable handle; the validation of the matched hyperprior as a section of the
|
|
13
|
+
metabeta paper; a standalone paper only if the per-quirk ablation and a second consumer give it
|
|
14
|
+
a finding the other papers do not carry.**
|
|
15
|
+
|
|
16
|
+
## Why item 5 or 6 alone is thin
|
|
17
|
+
|
|
18
|
+
- At item 5 TabDGP is a simulator plus two self-chosen certificates. The two-sample test and the
|
|
19
|
+
containment test run on a summary vector we picked, against a bar we set, so they show
|
|
20
|
+
consistency with the registry on those statistics, not that training on the generator helps.
|
|
21
|
+
- The new idea, a hyperprior for grouped tables measured against mixedbench's real tables
|
|
22
|
+
instead of hand-tuned like TabICL's or TabPFN's prior, is a component. The evidence that a
|
|
23
|
+
component matters is downstream: an amortized posterior trained on it against one trained on
|
|
24
|
+
something simpler, scored on real tables. That evidence lives in metabeta.mixed, not here.
|
|
25
|
+
- A fourth paper from one project reads as salami slicing unless it carries a finding of its own.
|
|
26
|
+
|
|
27
|
+
## What would make a standalone paper
|
|
28
|
+
|
|
29
|
+
1. **The downstream ablation.** An amortized posterior, or a prior-data fitted network (PFN),
|
|
30
|
+
trained on TabDGP, on an i.i.d. baseline prior and on a TabICL-style prior, scored on
|
|
31
|
+
mixedbench's real tables against its reference posteriors. Needs metabeta.mixed's slice A1.
|
|
32
|
+
2. **Which quirks matter.** Each quirk axis switched off in turn, the downstream effect
|
|
33
|
+
measured. Tells the field which properties of real tables a prior must reproduce; cheap
|
|
34
|
+
once the training loop exists, and the result most likely to be cited outside this stack.
|
|
35
|
+
3. **A second consumer.** Item 6's survival extension for metasurv turns metabeta's covariate
|
|
36
|
+
generator into a prior for tabular amortized inference in general.
|
|
37
|
+
4. **The quirk census** from mixedbench's measurement pass (roadmap item 3): how common group
|
|
38
|
+
confounding, rare levels, heaping and near dependence are across real grouped tables. The
|
|
39
|
+
mixedbench paper plans a registry census; which paper owns the quirk statistics is decided
|
|
40
|
+
before the mixedbench paper is drafted, or the TabDGP paper is left with the ablation alone.
|
|
41
|
+
|
|
42
|
+
## Considered options
|
|
43
|
+
|
|
44
|
+
- **A standalone paper at item 5.** Rejected above: no downstream result, a self-set bar.
|
|
45
|
+
- **No paper at all, the package referenced from the metabeta paper.** The cheapest; loses a
|
|
46
|
+
citable handle for standalone users and the per-quirk result, which belongs to no other
|
|
47
|
+
paper.
|
|
48
|
+
- **Package release plus JOSS, validation in the metabeta paper, a standalone paper
|
|
49
|
+
conditional on 1–3.** Chosen.
|
|
50
|
+
|
|
51
|
+
## Venues
|
|
52
|
+
|
|
53
|
+
| content | venue |
|
|
54
|
+
|---|---|
|
|
55
|
+
| package with the proofs, no downstream result | JOSS (Journal of Open Source Software): short, a DOI, the software is what is reviewed |
|
|
56
|
+
| plus the ablation and the quirk study | TMLR (Transactions on Machine Learning Research): rolling, judged on correctness |
|
|
57
|
+
| same, with a large per-quirk effect | NeurIPS Datasets & Benchmarks (not the same cycle as mixedbench's) or AISTATS |
|
|
58
|
+
| a test of reception first | the NeurIPS Table Representation Learning workshop |
|
|
59
|
+
|
|
60
|
+
## Consequences
|
|
61
|
+
|
|
62
|
+
- The roadmap gains a "Release and paper" section: the release with JOSS, the quirk census
|
|
63
|
+
ownership, the ablations, and the conditional paper.
|
|
64
|
+
- The proofs' summary vector and bar are documented as consistency checks, never claimed as
|
|
65
|
+
realism in the README or a paper.
|
|
66
|
+
- The per-quirk ablation is designed so that each quirk axis can be switched off by an
|
|
67
|
+
override, which item 4's hyperprior already allows; no extra code is planned for it here.
|