# Recovering structure from data

> Source: <https://www.konjugate.com/2026/08/recovering-structure-from-data.html>
> Published: 2026-08-26 10:25:52+00:00

Every other page has started from a model you build, by hand or by description. This one starts from data instead: a CSV of time-series measurements, with no model at all yet. Causal inference proposes candidate nodes and relationships from it — Granger-style, checking whether one column's past values predict another's — for you to review before anything becomes part of your model.

For the statistics behind this — lagged partial correlation, ridge regression, why a naive contemporaneous screen gets it wrong — see [Recovering a Causal Graph from a System](https://www.konjugate.com/2026/08/recovering-causal-graph-from-system.html). This page is about the workflow, not the math.

The example CSV here is deliberately small: 60 rows, two columns, one genuine lagged relationship built in (`columnB`

responds to `columnA`

's *previous* value, `columnA`

responds to nothing) — enough to see the whole flow clearly without a large dataset's noise.

Open **Causal inference** from the toolbar and choose a CSV — a numeric, evenly spaced time column, then one column per variable.

A column whose name exactly matches an existing node's state in your current model binds to it instead of creating a new one — useful for adding a data-derived relationship onto a model you've already partly built by hand. On a blank canvas, as here, every column creates something new.

**Nonlinearity** controls whether the fit stays linear, is forced to a chosen polynomial degree, or lets the tool pick whichever fits better per relationship — linear is the right default unless you have a specific reason to expect curvature.

**Run inference** screens every pair of columns and proposes one directed edge per relationship it finds evidence for.

**Lagged** means the source's past value predicts the target — a real, if weak, causal claim. A pair that's clearly related but with no clear direction gets tagged **correlation-only** instead, rather than being silently dropped or given a direction it doesn't support. Every candidate has its own checkbox — nothing is all-or-nothing.

**Import selected** commits every checked candidate as one undoable step: new nodes for any unmatched column, and real relationships with real fitted equations.

Nothing about an imported relationship is special or locked — opening it looks exactly like any hand-authored one from "The graph canvas."

That fitted coefficient is worth sitting with for a second: nothing here was told the true relationship was `3 × previous columnA`

. It was recovered, from 60 rows of noisy numbers, close enough to be convincing — and now that it's a real equation on a real relationship, it can be edited, deleted, connected to other nodes, or run, exactly like everything else in this documentation series.

This closes out modeling and data — building by hand, describing in language, or recovering from data, and running and reading back whatever the model produces. The last page covers geometry and add-ons: what a node looks like, and how completed results reach visualizers beyond the built-in plot.
