Find patterns and insights in tabular and JSON data. O*NET 30.0 + SEC 2026. One command: ./run.sh
  • Python 99.2%
  • Shell 0.5%
  • Makefile 0.3%
Find a file
brahm 6fe7be12ac v1.0.0: replace title lexicon with unsupervised discovery
The v0.x core was an opinionated VALID/INVALID title ruleset. This
replaces it with detectors that only emit measured patterns:

  concentration, outliers, ups/downs, associations, subgroups, clusters

Benchmark is planted statistical structure (Pareto, crash, correlation,
near-FD, 3× subgroup, outliers, missing-together) — 8/8 recovered.

On real SEC 2026 companyfacts the same engine reports asset Gini 0.69,
top-3 rows holding 55% of assets, and assets↔equity ρ=+0.87.
2026-08-13 23:50:43 +00:00
datasets v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
docs v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
fixtures patternlab v0.3.0 — find patterns in tabular and JSON data 2026-08-13 23:19:55 +00:00
gold v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
loop v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
patternlab v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
results v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
tests v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
.gitignore patternlab v0.3.0 — find patterns in tabular and JSON data 2026-08-13 23:19:55 +00:00
CHANGELOG.md v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
LICENSE patternlab v0.3.0 — find patterns in tabular and JSON data 2026-08-13 23:19:55 +00:00
Makefile v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
README.md v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00
requirements.txt patternlab v0.3.0 — find patterns in tabular and JSON data 2026-08-13 23:19:55 +00:00
run.sh v1.0.0: replace title lexicon with unsupervised discovery 2026-08-13 23:50:43 +00:00

patternlab

Unsupervised pattern and insight discovery for tabular and JSON data.

It does not know what a job title is, what “valid” means, or what a high-value contact is. It measures the table and writes down what is unusual: concentration, outliers, ups and downs, associations, subgroups, clusters.

./run.sh

Or on any file:

python3 -m patternlab analyze path/to/file.csv
python3 -m patternlab analyze path/to/file.json
python3 -m patternlab analyze path/to/file.jsonl --only concentration,outliers,trends

Python 3.11+, stdlib only. Repo: https://git.binary.ovh/brahm/patternlab


What a finding looks like

The top 10% of rows (12) hold 81% of the sum of 'wealth'.
'units' and 'revenue' move together (Spearman ρ=+0.97, n=400).
'sales' dropped 61% in 2025-10 (118 → 46).
When segment='enterprise', 'spend' is higher than the rest (3.1× the global mean).
8 outliers on 'spend' (values from 401 to 478; strongest robust z=+9.4).
'region' nearly determines 'tax_rate' (purity=97%).

Each line is a number taken from the file. Nothing is emitted because a lexicon said so.

Full map: docs/DISCOVERY.md.


Step by step

1. Clone

git clone https://git.binary.ovh/brahm/patternlab.git
cd patternlab
chmod +x run.sh

2. Run the lab

./run.sh

This:

  1. Fetches O*NET 30.0 and SEC 2026 lists (cached after the first time).
  2. Writes a synthetic table with known statistical structure.
  3. Checks that those structures are recovered (results/latest/bench.md).
  4. Writes findings for the synthetic table and the public tables.

3. Read

file what
results/latest/planted_stats/insights.md did we see the planted Pareto / crash / correlation?
results/latest/sec_companyfacts_2026/insights.md concentration and outliers in 2026 10-K numbers
results/latest/onet_occupations/insights.md subgroups / associations in O*NET 30.0
results/latest/bench.md planted-pattern recall

4. Point it at your file

CSV, TSV, JSON array, JSONL, nested JSON (flattened).

python3 -m patternlab analyze contacts.csv --out results/mine

--label some_column is optional. If you pass it, that column is treated as a grouping field for subgroups. It is not a validity flag.

--only concentration,outliers,trends,association,subgroup,cluster runs a subset.

5. How we know it works

gold/planted_stats.jsonl is built with:

  • Pareto wealth (a few rows hold most of the sum)
  • revenue ≈ 2.1 × units
  • sales crash in the last quarter
  • region nearly determines tax_rate
  • segment=enterprise has ~3× spend
  • 8 injected spend outliers
  • status dominated by one value
  • email and phone missing together

The bench asks whether those structures appear in the report.


Detectors

detector looks for
concentration Gini, top-10% share, category dominance, HHI
outliers IQR + MAD robust z; rows extreme on 2+ columns
trends auto date column; overall up/down, biggest jump, biggest drop, recent vs prior
association Spearman, Cramér's V, near functional dependencies, missing-together
subgroup category slices where a numeric mean is ≥0.65σ from global
cluster k-means on standardized numerics, described by distinctive features

No domain lists. Thresholds live in patternlab/config.py.


Data used for the public demos

  • O*NET 30.0 (US DOL, CC BY 4.0, 23 Jul 2026)
  • SEC company tickers + a 39-issuer companyfacts sample (2026-preferring 10-K)
  • ATS-shaped rows derived from those sources (no private ATS scrape)

The engine does not special-case any of them.


Versions

v0.1v0.3 were an opinionated title-validation experiment. v1.0.0 replaces that core with the discovery engine above.


License

MIT. O*NET strings remain CC BY 4.0.