Downloads · 30 days
0
robertollweb/matrixai-readmission-risk-synthetic
matrixai-readmission-risk-synthetic is a tabular classification model from robertollweb. Use it for the tabular classification task on the model card, and read the license before you ship it in a product. The card lists the license as agpl-3.0.
A classification with its TRIPOD+AI record written by the command.
Downloads · 30 days
0
Access
Public
Updated Aug 30, 2026
Repo size
4 KB
Likes
0
Public
Click a slice to open those files.
.json34.2 KB · 34%
From the Hugging Face model README
A classification with its TRIPOD+AI record written by the command.
THE TRAINING DATA IS SYNTHETIC. There is not one real patient in it. All 400 rows were generated by a two-line rule that a person wrote, which ships in this package as
data_recipe.txt. A model trained this way is not clinically validated.THIS IS NOT FOR USE WITH PATIENTS. It is a demonstration of traceability, not a medical device and not a clinical decision aid. See Not for use with patients.
A 4-input feed-forward classifier (Dense 32 relu → Dense 16 relu → Dense 2 softmax) that maps
four made-up admission variables to a probability over two labels, alto (high) and bajo (low).
It exists to show one thing end to end: that a model can travel with the rule its data came from, the digests of every artefact and the environment it was trained in — and that from all of that a command can then write a TRIPOD+AI record, including the boxes that record cannot fill.
It is one of the three reproducible cases at
matrixaistudio.org/casos. MatrixAI can also build a
model from a plain-language description; this case was not made that way, it was made from the
.mxai and the recipe published here.
The rule that decided every label, verbatim from data_recipe.txt:
alto: edad > 75 OR reingreso_previo > 0.5
DEFAULT: bajo
That rule is the whole ground truth. Learning it is not a clinical finding.
The rule uses two of the four inputs. dias_ingresado and num_diagnosticos appear in
neither clause: they are noise by construction, and no label anywhere depends on them. The .mxai
declares an AUDIT / EXPLAIN Input -> Classifier block, but no attribution or explanation is
published with this case, so there is nothing here that shows what the network did with those
two columns.
The four inputs are continuous scalars, including the ones whose names sound discrete.
model.mxai declares all four as Scalar over a range: edad [18, 100], dias_ingresado
[0, 60], num_diagnosticos [0, 15], reingreso_previo [0, 1]. The generator samples them as
continuous values — regenerating the dataset with the command below gives rows such as
num_diagnosticos 2.7471 and reingreso_previo 0.3372. That is why the recipe thresholds at
> 0.5 rather than testing a boolean, and why the bundle's own example_input.json uses
num_diagnosticos 7.5. Read num_diagnosticos as "a number in [0, 15]", not as a count of
diagnoses.
accuracy below was measured on a validation
split of the same synthetic dataset the model trained on.simulate_only. This bundle only provides predictions."Python 3.10 or newer (requires-python = ">=3.10"), then pip install "matrixai-core[export]".
No account, no LLM key, no GPU. Put modelo.mxai, modelo.mxtrain and receta.txt in an empty
directory; the commands generate the rest.
matrixai generate-dataset modelo.mxai --training modelo.mxtrain \
--rows 400 --seed 20260825 --mode coherent --recipe receta.txt -o datos
matrixai train modelo.mxai --training modelo.mxtrain --output runs/v1 \
--recipe receta.txt --dataset-manifest datos/classifierproject-synthetic-manifest.json
matrixai export-bundle modelo.mxai --params runs/v1/params.best.json \
--outdir paquete --training modelo.mxtrain --data-recipe receta.txt --from-run runs/v1
zip -r paquete.zip paquete # or: python -m zipfile -c paquete.zip paquete
matrixai verify paquete.zip --retrain
matrixai report paquete --tripod --locale en -o ficha_tripod.en.md
The zip line is not decoration. matrixai export-bundle writes a directory — --outdir
is its only output flag and it has no zip option — so nothing in the published command list
produces a paquete.zip on its own. In this project the zip is made by the build script. Without
that line the verify step has no file to open.
--mode coherent samples the inputs inside the ranges the .mxai declares and lets the recipe
decide each label (matrixai generate-dataset --mode: "random (uniform) or coherent
(model-guided labels)"; --recipe: "the rule that decides the target from the inputs").
Verify the ZIP, not the freshly built directory. Verifying the directory leaves datos/ on
disk, and the retrain stage picks the dataset up from there instead of rebuilding it from the
recipe — which is exactly the step being checked. The same goes for __pycache__: importing
predict.py from inside the bundle writes one, and matrixai verify counts it as a file the
manifest does not name (all four stages then come back INCOMPARABLE). Use a pristine copy.
What matrixai verify paquete.zip --retrain printed on the machine that built this package
(salida.txt, step 5 — literal stdout):
manifest PASS
R1 PASS
training PASS
R3 PASS
That is not what you will get. Measured on 2026-08-30 against the published paquete.zip
with matrixai-core 1.7.0 — which is what the pip install line above installs today:
$ matrixai verify paquete.zip --retrain --locale en
manifest PASS
R1 PASS
training PASS
R3 INCOMPARABLE — the tolerance was measured for the package's own environment (f73756abfe0d07df…) and this one is different (364849887da933a3…), so a difference here would not prove the package wrong
$ echo $?
3
INCOMPARABLE is one of the four verdicts the tool defines (PASS, FAIL, INCOMPARABLE,
NOT_RUN) and it means "I could not check this" — a different thing from FAIL. Expect it,
and expect exit 3. (The second digest will be different again on your machine; it is a digest of
your environment.) Exit codes, from the bundle's own README: 0 nothing failed · 2 something
does not match · 3 it could not be checked.
Pinning the core version will not get you four PASS. environment_sha256 covers the
matrixai version, the exact CPython build string, the kernel release and the
numpy/onnx/onnxruntime/torch versions (matrixai/export/reproduce.py, build_environment).
Measured here: recomputing that digest on this machine with only the version string forced to
1.6.0 reproduces f73756abfe0d07df… exactly — so on this machine the core version is the one
field that moved, and 1.6.0 is still on PyPI. On any other machine the CPython build string and
the kernel release move too, and no pin brings those back. R3's tolerance is scoped
same_environment_same_seed; when the environment is not the same, the core says so instead of
manufacturing a PASS.
| Stage | What it checks |
|---|---|
manifest | Every artefact in the package matches the sha256 the manifest declares, and nothing travels that the manifest does not name. |
R1 | The dataset rebuilt from the recipe has the full sha256 the package declares. |
training | Training runs to completion with what the package carries inside. |
R3 | The metrics of that fresh run fall inside their declared tolerance. |
Stage descriptions: https://matrixaistudio.org/manual/proof.
reproduce.json → environment (environment_sha256
f73756abfe0d07dffabba936f5e66218dd56e5bf3ebc8ee0c507ac69bb3f2f15):
| matrixai | 1.6.0 |
| python | 3.12.3 (CPython) |
| platform | Linux 6.8.0-137-generic, x86_64, glibc 2.39 |
| packages | numpy 2.4.4 · onnx 1.21.0 · onnxruntime 1.26.0 · torch 2.11.0+cpu |
| backend / device | stdlib / cpu (reproduce.json → generation) |
| exported at | 2026-08-26T15:55:14.631725+00:00 (export_manifest.json → exported_at) |
Both published metrics declare tolerance_abs: 0.0 with tolerance_scope: "same_environment_same_seed", so an exact match is only claimed inside that environment with
those seeds. If your digests come out different, something changed and it is worth knowing what.
Both figures come from reproduce.json → metrics, and both carry the digest of the dataset
they were measured on — 1cefbf74e237efdae2f6e06d7b9c5141ed815cccbd547aa18341ab7a79c96e65.
| Metric | Value | Split | Source |
|---|---|---|---|
accuracy | 0.96875 | validation | reproduce.json → metrics[0]; also salida.txt step 2 (Accuracy: 0.968750) |
best_validation_loss | 0.07562131317942544 | validation | reproduce.json → metrics[1]; also salida.txt step 2 (Best validation loss: 0.075621) |
What each metric says is missing about itself. reproduce.json gives every metric an
incomplete list, and the two lists are not the same:
accuracy → evaluator, evaluator_version, tolerance_rel are all null.best_validation_loss → evaluator, evaluator_version, aggregation, tolerance_rel are all null.0.96875 is 62/64. The package does not record how many rows were used
(artifacts.dataset.rows_used is null, and so is sha256_prepared; a null is an answer here,
not a zero) — but that does not mean it cannot be known, and leaving it at "not recorded" would be
half the truth. The 400 generated rows are split into a 320-row train CSV and an 80-row eval CSV
(salida.txt step 1). modelo.mxtrain reads only the 320-row train CSV and splits that again
train=0.8 / validation=0.2 seed=42. Measured by re-running the published commands and reading
runs/v1/training_trace.json: the validation set is 64 rows, and 0.96875 × 64 = 62. So two
rows are wrong, and one row is worth 1.56 percentage points.
What 0.96875 is worth against the base rate. Regenerating the dataset with the exact command
above — the same regeneration whose R1 PASS says it matches the dataset digest the package
declares, and which reproduces the published training output exactly (Best epoch: 29,
Best validation loss: 0.075621, Accuracy: 0.968750) — gives a 320-row training CSV of
205 alto / 115 bajo, a majority-class baseline of 0.6406. In the 64-row validation split
the same re-run records 44 alto / 20 bajo, a baseline of 0.6875. So the model lands about
28 points above always answering alto, on a rule that is separable by construction.
Per class, from the same re-run (runs/v1/training_trace.json → validation_metrics; the
package publishes none of this, only the global accuracy, whose aggregation is "global"):
predicted alto | predicted bajo | |
|---|---|---|
true alto (44) | 42 | 2 |
true bajo (20) | 0 | 20 |
precision alto 1.0 / bajo 0.909091 · recall alto 0.954545 / bajo 1.0 · macro-F1 0.964562.
Both errors are in the same direction: two high-risk rows called low. The published package
contains no confusion matrix, no per-class metric and no class balance — those five lines were
measured here by re-running it.
From reproduce.json:
| rows generated | 400 (artifacts.dataset.rows) — salida.txt step 1: 320 train CSV + 80 eval CSV |
| rows used | null — not recorded by the package (measured on a re-run: 256 train / 64 validation) |
| dataset sha256 | 1cefbf74e237efdae2f6e06d7b9c5141ed815cccbd547aa18341ab7a79c96e65 |
| seeds | dataset 20260825 · split 42 · init 42 |
| generation | mode coherent, matrixai.synthetic.v1, recipe format matrixai.recipe.v1, warm_start: false |
| epochs declared / effective / ran | 60 / null / null (measured on a re-run: all 60 ran) |
| recipe verification | verified: true, code regenera_el_dataset |
| weights | source: "trained" |
| provenance | run_capture, schema 1.2, sha256 3dd3c04f819918ef70b96ac86ad28177740ae5eb656bcd44b1e0a0b537971cfa |
Two of the three epoch counts are missing, and the package says so. Only the declared 60 is
recorded; epochs_effective and epochs_ran are null, and the TRIPOD+AI record prints them as
_not available_. The console output of the training step (salida.txt) separately reports
Best epoch: 29 and run id efc59afa — that is stdout, not something the manifest carries.
manifest_sha256: 072ffdfca51a37b920cfbf7a90945922d3ddb5ea142501f25e77707e64b49a72
(canonicalisation: json:sort_keys=true,separators=(',',':'),ensure_ascii=true,utf-8).
files_covered: 16 — every file in the package except reproduce.json itself. A manifest cannot
carry its own digest inside; its integrity is declared by manifest_sha256, which is computed by
whoever builds the package. salida.txt step 3 lists 17 files in the bundle.
| Artefact | sha256 | matches_capture |
|---|---|---|
model.mxai | a164f4380120be24d6cc66ac564bc7af820498cdbcf0caf251398aa904410747 | true |
model.mxtrain | 45235ce15bb7744a43dc7aee32ef1622009be352e2d0926e0d3bd8d7feca18d6 | true |
data_recipe.txt | 90376b2c20ee3bd8ced0409bb7c9bc98116afa02174b118905af3289ab513a37 | true |
model.onnx | 99a730a24c58f1b58f5e98ec03f20f2d1148f8dca9c597272c7ad3b5513567bc | (covered by files) |
predict.py | 4ff7568981a683503c8480cf21f18b7c69f531c57f298d65ce346e60c9080bf1 | (covered by files) |
inference_spec.json | 3bb65450baa1c53ea374b8b1d02fbd7a62e0c068b71cfebd92ffae830d8d8c95 | (covered by files) |
Model identity (model_manifest.json, inference_spec.json, export_manifest.json):
model_hash mxai_9474e16a946fd170, parameter_schema_hash params_1f8b44696ed7d327,
parameter_set_id Classifier_initial.
export_manifest.json → equivalence_check: passed: true, max_abs_diff 1.1920928955078125e-07,
max_rel_diff 2.8725314183123877e-06, against atol 1e-05 / rtol 0.0001, over
n_samples 20 × 2 outputs. salida.txt step 3 prints the same check as
Equivalence PASS: max_abs_diff=1.19e-07. Those 20 vectors come from a generator with a fixed
default seed of 42 (matrixai/export/equivalence.py) — the same 20 points on every export, not a
fresh sample — and they are already-normalised inputs compared on the model's raw output. Twenty
fixed samples is what was checked; it is not a proof of equivalence over the input space.
The package predicts from raw, human-readable values with numpy and onnxruntime and
nothing else. predict.py applies the same normalisation and label mapping the model was
trained with, read from inference_spec.json.
unzip paquete.zip && cd paquete
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt # numpy>=1.24, onnxruntime>=1.16
python predict.py --input example_input.json
That reproduces expected_output.json exactly:
{"alto": 0.01409356389194727, "bajo": 0.9859064817428589}
From your own code:
from predict import MatrixAIModel
model = MatrixAIModel() # loads inference_spec.json next to predict.py
model.predict({"edad": 92, "dias_ingresado": 10,
"num_diagnosticos": 3, "reingreso_previo": 0.9})
The field names and the labels are Spanish because they are the contract: input_order is
["edad", "dias_ingresado", "num_diagnosticos", "reingreso_previo"] and the output labels are
["alto", "bajo"]. What happens if you rename one, measured: passing age instead of edad
raises MatrixAIModelError: Missing required field 'edad'. — no hash is involved. The hash check
that does exist in predict.py (_verify_hash) compares the model_hash and
parameter_schema_hash in inference_spec.json against the metadata embedded in model.onnx; it
says nothing about field names. What editing inference_spec.json would break is its sha256 in
reproduce.json, and with it the manifest stage of matrixai verify.
The raw ONNX graph (Input, shape [-1, 4], float32 → Classifier_out3, shape [-1, 2],
opset 17) expects an already-normalised vector. Prefer predict.py.
The first two are the files published with the case, and their outputs are the literal stdout
recorded in salida.txt step 4; the third ships inside the bundle with its answer in
expected_output.json. All three were re-run from the published paquete.zip while writing this
card and came out digit for digit identical.
| Input file | Raw record | Output | Which clause of the rule fires |
|---|---|---|---|
entrada.json | edad 92, dias_ingresado 10, num_diagnosticos 3, reingreso_previo 0.9 | {"alto": 1.0, "bajo": 9.931520189576659e-11} | both: edad > 75 and reingreso_previo > 0.5 |
entrada_joven.json | edad 25, dias_ingresado 2, num_diagnosticos 1, reingreso_previo 0.0 | {"alto": 0.0002168944920413196, "bajo": 0.9997830986976624} | neither |
example_input.json (in the bundle) | edad 59, dias_ingresado 30, num_diagnosticos 7.5, reingreso_previo 0.5 | {"alto": 0.01409356389194727, "bajo": 0.9859064817428589} | neither (0.5 is not > 0.5) |
So they contrast the two ends of the rule: everything on, and everything off. They do not
test the OR separately. No published example has a high edad with no prior readmission, or
the reverse, so these files do not show that either clause fires on its own.
"alto": 1.0 is not certainty. bajo is 9.93e-11, and float32 cannot represent
1 − 9.93e-11 (its epsilon is about 1.19e-07), so the complement rounds to exactly 1.0. It
is a saturated softmax on a synthetic separable rule, not a calibrated probability of anything.
TRIPOD+AI is a 27-item reporting checklist for studies that develop or validate a clinical
prediction model (Collins et al., BMJ 2024;385:e078378 — an external reference, not
something any file in this case states). matrixai report <package> --tripod --locale en writes
a record from what the run already captured. The document says of itself, in its own first lines:
"Every line comes from what the run recorded; what is not known is said" — that is the
document's claim about the document, quoted here rather than endorsed. What can be checked, and
is checked below, is which boxes came out filled and which came out empty. The full output ships
with the case as ficha_tripod.en.md (ficha_tripod.md is the Spanish one). Its first lines also
say the data is synthetic and that this is not a medical device.
The record does not travel inside the package. The 17 files in paquete.zip do not include
it; it is generated afterwards, from the package, and published alongside the case.
Filled in from the run: data source (coherent), rows, dataset digest, predictors with their
declared ranges, split and the three seeds, the data recipe verbatim, the architecture and
hyperparameter digests, epochs declared, the environment, both performance metrics with the
dataset digest they were measured on, and model availability (ONNX + predict.py).
One caveat on that list: the record's "Rows that trained: 400" is the number of rows generated. Training read the 320-row train CSV and, after the 80/20 split, fitted on 256 of them — see the metrics section above.
Printed as _not available_, because the run did not record them: excluded columns; epochs
effective; epochs ran.
Named as boxes the record cannot fill at all — quoted from ficha_tripod.en.md:
Producing a document laid out for a checklist is not the same as meeting the checklist, and this record is not an item-by-item response to the 27 items: it has five sections, and seven of its headings are empty here — three because the run neither declares nor computes them (missing data, calibration, subgroup fairness), and four because a person has to write them (funding, conflicts, ethical approval and study registration, intended use and target population).
reproduce.json states its own claim: "This manifest
proves the package is internally consistent and reproducible: every artifact needed to rebuild
this model travels here with its digest, and each one matches the authoritative capture the
core recorded while training it. It does NOT prove authorship or authenticity: signatures are
out of scope here." No signature travels with this package.accuracy 0.96875 is not a generalisation claim. It is measured on the validation split
of the same generated dataset, produced by the same rule and the same seed the model trained
under. There is no data of any other provenance anywhere in this case. It says the network
learned a two-line rule; it says nothing about any population.salida.txt step 1
records Eval: datos/classifierproject-synthetic-eval.csv (80 rows), and both metrics in
reproduce.json declare "split": "validation". There is no published number on that eval file.dias_ingresado and num_diagnosticos are in no
clause of the rule, and no attribution is published, so nothing here shows whether the network
learned to ignore them.R3 is a tolerance check, not an independent evaluation — and off the machine that built
the package it does not even run to a verdict: it comes back INCOMPARABLE and verify exits
3. Measured; see the reproduction section above.salida.txt is stdout only. The build script captures the standard output of each command;
anything a command wrote to standard error is not in that transcript. Absence of a warning
there is not evidence that no warning was issued.model-index metrics block. That widget presents a
number as a checked result; 0.96875 on a synthetic, separable rule with a 0.6875 base rate is
not a result you should read off a badge.paquete.zip holds the whole bundle — the 17 files salida.txt step 3 lists: model.onnx,
predict.py, inference_spec.json, model.mxai, model.mxtrain, params.best.json,
data_recipe.txt, model_manifest.json, export_manifest.json, reproduce.json,
requirements.txt, example_input.json, expected_output.json, README.md, and
space/README.md, space/app.py, space/requirements.txt. Sixteen of them carry a sha256 in
reproduce.json; the seventeenth is reproduce.json, which cannot hash itself.
Published alongside it: modelo.mxai, modelo.mxtrain, receta.txt, entrada.json,
entrada_joven.json, reproduce.json, salida.txt, ficha_tripod.md, ficha_tripod.en.md.
AGPL-3.0-only. The exported predict.py carries SPDX-License-Identifier: AGPL-3.0-only,
© 2026 Roberto Llamosas Conde.
pip install "matrixai-core[export]"MatrixAI builds, trains, audits and deploys a neural network from a plain-language description or a CSV, and emits a cryptographic receipt at each step. It is open source under AGPL-3.0, and every exported package predicts with no MatrixAI installed.
This model is not a demo to look at — it is a case you can redo, and the tool that produced it is free.
MatrixAI Studio turns a written description, or a CSV you already have, into a neural network you can question: it builds it, trains it, and emits a cryptographic receipt at every step, so anybody can re-check what you claim. It runs on your own machine — no account, no cloud, no API key.
pip install matrixai-coreIf something on this page is not true, it should be visible from the outside. That is the whole point of publishing the package and not just the numbers.