| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
An audit of NOTEARS and DAGMA through the lens of varsortability, plus a directed↔undirected (Bayesian-network ↔ Markov-network) bridge on real protein- signaling data.
Continuous-optimization structure learners such as NOTEARS (Zheng et al., 2018) and DAGMA (Bello et al., 2022) post strong numbers on simulated DAG benchmarks. Reisach et al. (2021) showed that much of that success can be an artifact called varsortability: in generically parameterized structural equation models, marginal variance grows along the causal order, so the order leaks through the variances and a trivial variance-sorting baseline can match the sophisticated methods.
This project reproduces that effect in a clean, uniform harness, pushes past the usual "just standardize the data" takeaway using the scale-invariant R²-sortability, and then turns the same machinery on the real Sachs protein-signaling benchmark — where it also compares a directed model against an undirected Gaussian Markov network learned on the identical data. The reimplementation of prior methods is deliberately not the contribution; the audit harness, the residual-structure analysis, and the directed↔undirected bridge are. See docs/design.md for the full rationale and limitations.
All numbers come from the scripts in src/dag_audit/experiments/ on the committed configuration. Seed counts are small for fast reproduction, so treat these as illustrative and expect run-to-run variation.
1. Learner "skill" tracks varsortability. Across data spanning varsortability 0.12 → 1.00, the trivial sortnregress baseline's F1 correlates with varsortability at Pearson r ≈ 0.96 — it is essentially a varsortability meter — and at high varsortability it is competitive with, and often ahead of, NOTEARS and DAGMA. High benchmark scores alone do not demonstrate discovery ability.
2. Standardization removes the signal. On high-varsortability data (≈0.92), standardizing every variable to unit variance drives varsortability to ≈0.50 and collapses every method's F1 — the trivial baseline most of all.
3. But "just standardize" is too glib. Standardization removes varsortability (→0.50) but not the scale-invariant R²-sortability (stays ≈0.68), and the learners keep an above-baseline edge on standardized data. The honest lesson is to report scale-invariant structure, not to assume standardization makes a benchmark safe.
4. Real biology behaves as the thesis predicts. On Sachs, varsortability is only ≈0.36 — the synthetic crutch is absent — and the learners recover the 17-edge consensus network poorly, matching the published literature:
| Method | SHD | F1 | Precision | Recall |
|---|---|---|---|---|
| NOTEARS | 21 | 0.21 | 0.27 | 0.18 |
| DAGMA | 18 | 0.28 | 0.33 | 0.24 |
| sortnregress | 39 | 0.25 | 0.17 | 0.47 |
5. Directed vs. undirected on the same data. Moralizing the learned NOTEARS DAG yields ≈10 undirected edges, while a graphical-lasso Markov network fit to the same data has ≈35, overlapping only modestly (Jaccard ≈0.25). The undirected model asserts many conditional dependencies the sparse DAG does not — a concrete view of the Bayesian-network ↔ Markov-network representation gap on correlated biological data.
git clone https://github.com/baksho/dag-discovery-audit.git
cd dag-discovery-audit
pip install -e .This installs the dag_audit package and its dependencies (numpy, scipy, scikit-learn, networkx, matplotlib, and the official dagma package).
No external data is required for experiments 1–3:
python scripts/run_all.pyResults (JSON) are written to results/ and figures to results/figures/.
Experiment 4 needs the Sachs dataset. Fetch the CC BY 4.0 mirror on first use:
SACHS_DOWNLOAD=1 python -m dag_audit.experiments.exp4_sachs_bn_mnThe canonical origin of the data is the bnlearn distribution (https://www.bnlearn.com/research/sachs05/); see src/dag_audit/data/sachs.py for provenance, the consensus-graph choice, and the observational-subset caveat.
Everything is a plain function. A minimal end-to-end example:
from dag_audit.data import simulate_linear_sem, standardize
from dag_audit.methods import default_learners
from dag_audit.metrics import varsortability, structural_scores
ds = simulate_linear_sem(d=15, noise_scale_strategy="increasing", seed=0)
print("varsortability:", varsortability(ds.X, ds.W_true))
learn = default_learners()["NOTEARS"]
W_est = learn(ds.X)
print("F1 vs truth:", structural_scores(W_est, ds.B_true).f1)The directed↔undirected bridge:
from dag_audit.methods import graphical_lasso_graph, moralize, compare_moral_vs_ggm
W_dag = default_learners()["NOTEARS"](ds.X)
A_ggm = graphical_lasso_graph(ds.X)
print(compare_moral_vs_ggm(W_dag, A_ggm).as_dict())src/dag_audit/ data/ synthetic linear SEMs, the Sachs loader, and the optional GRN simulator methods/ from-scratch NOTEARS, a DAGMA wrapper, baselines, and the undirected/bridge tools metrics/ varsortability, R2-sortability, and structure-recovery metrics experiments/ the four runnable experiments described above scripts/ run_all.py tests/ pytest suite for the metrics, NOTEARS, and moralization docs/ design.md — rationale, results, and limitations
pip install -e ".[dev]"
pytestThe suite checks varsortability on hand-built and generated cases, that the from-scratch NOTEARS returns an acyclic graph and recovers a known chain, SHD behavior on reversed/perfect graphs, and that moralization marries parents of a v-structure.
Full detail in docs/design.md.
MIT — see LICENSE.
| Back | FazBrowse Home | New Git URL |