meddeid-data
Generate synthetic clinical notes with exact character-offset de-identification annotations. The package includes locale generation profiles, structured case models, deterministic renderers, clinical resource pools, Synthea integration, and dataset-quality checks.
The nl-BE profile samples Belgian resources from meddeid-language-nl.
The nl-NL profile shares only the locale-neutral clinical case structure. It
has a dedicated Netherlands renderer and judge, Netherlands-specific names,
addresses and institutions, and BSN, BIG, EPD/ZIS, postcode, +31 phone, and
example.nl conventions. It is available as generation code; this migration
does not generate or publish a corpus.
The unversioned en-GB and en-US locale profiles sample independently released, audited
name, address, institution, occupation, and terminology records from
meddeid-language-en. Bare en is rejected because date order, addresses,
identifiers, phone ranges, and clinical terminology are locale-specific.
Belgian DEDUCE is not a runtime dependency.
Start with the suite guide to preparing and annotating data. This repository remains authoritative for import, project, split, generation, and validation commands.
Installation
python -m pip install meddeid-data
Install Parquet support with
python -m pip install 'meddeid-data[parquet]'.
Generate synthetic data
Generation defaults to the released Dutch/Belgian profile:
meddeid-data generate --count 100 --output synthetic.jsonl \
--pretty-output synthetic.pretty.json \
--judge-report synthetic-report.md
meddeid-data validate synthetic.jsonl
Select a language and locale explicitly for multilingual generation:
meddeid-data generate --language-profile en-GB \
--count 100 --output synthetic.en-gb.jsonl \
--judge-report synthetic.en-gb-report.md
Use --language-profile en-US for the separate United States and territories
profile. English synthetic generation permits exactly the 14 token-classifier
labels and rejects Anonymize_Other during rendering, review, and export. The
full taxonomy remains valid for non-generation interoperability.
The local nl-NL profile can be selected in the same way. Its availability
does not imply that a Netherlands corpus exists or that the released Dutch
model has been trained or evaluated on Netherlands clinical text.
The ordered English synthetic allowlist is exactly
Address_Location:Caregiver, Address_Location:Other,
Address_Location:Patient, Age_Birthdate, Contactdetails, Date,
ID:Caregiver, ID:Patient, Name:Caregiver, Name:Other, Name:Patient,
Organization:Healthcare, Organization:Other, and Profession.
Every dataset manifest pins both language_profile and the complete
meddeid.generation-profile.v1 descriptor, including resource hashes. Unknown
profiles fail before generation with the installed-provider discovery result.
Use existing Synthea CSV output or ask the tool to create it:
meddeid-data generate --count 1000 --output synthetic.jsonl \
--synthea-csv-dir path/to/synthea/output/csv --require-synthea
meddeid-data generate --count 1000 --output synthetic.jsonl \
--auto-synthea --require-synthea
The two-stage workflow keeps structured cases available for inspection:
meddeid-data build-cases --language-profile en-GB \
--count 100 --output cases.jsonl
meddeid-data render-cases cases.jsonl --output synthetic.jsonl
Case records pin their generation profile, so render-cases resolves it without
requiring the selection again. Passing an incompatible profile is rejected.
meddeid-data sample provides a small offline generation run through the same
profile contract.
Batch-gated production corpora
Use the production state machine for paid generation or any corpus that needs
personal review and a sealed benchmark. Unlike generate, it records every
batch transition and refuses to finalize unsigned or changed documents:
meddeid-data production init ./english-production \
--profile en-GB,en-US \
--count 7000 --batch-size 500 --benchmark-count 300 \
--mode remote --allow-remote --backend english-luna \
--author-model gpt-5.6-luna --reasoning-effort low \
--max-cost-usd 32.68
meddeid-data production status ./english-production
meddeid-data production run ./english-production --until-gate
run --until-gate stops before personal review. Record one content-bound
decision for every document, then sign off that batch:
meddeid-data production review ./english-production \
--batch-index 0 --document-id en-gb-synthetic-00001 \
--decision accept --reviewer reviewer-id
meddeid-data production sign-off ./english-production \
--batch-index 0 --reviewer reviewer-id --notes 'All 500 reviewed'
Decisions are accept, edit, regenerate, or reject. Changing a document
invalidates its decision and the batch sign-off. The corpus-wide writer lock
prevents a second batch from spending concurrently. The attempt ledger counts
failed and superseded API requests. --max-cost-usd stops new work when the
recorded spend reaches the guardrail and, after the first attempts exist,
before a batch whose projected completion would cross it. The provider account
ledger remains authoritative, so leave headroom for requests already in flight.
Use replace for a manually corrected canonical document; the old version and
both hashes remain in the audit trail. Use invalidate when the document must
be independently re-authored on the next run:
meddeid-data production replace ./english-production \
--batch-index 0 --document corrected-document.json \
--editor reviewer-id --reason 'Corrected two PII boundaries'
meddeid-data production invalidate ./english-production \
--batch-index 0 --document-id en-gb-synthetic-00001 \
--reason 'Regenerate with a less common address format'
Both operations invalidate the old automated report, document review, batch sign-off, and any derived final split. After every batch is accepted:
meddeid-data production finalize ./english-production
Finalization repeats canonical-label and diversity checks, refuses exact, PII-normalized, or configured near duplicates, and creates deterministic profile/document-family-stratified development and benchmark files. The English 7,000-document preset resolves to 6,700 development documents and a 300-document benchmark with 150 documents per locale and 25 per locale/document-family cell.
Remote authoring is a plugin boundary (meddeid.production_backends). The
built-in english-luna backend implements the current English pipeline;
another language can provide a backend without adding locale branches to the
production state machine.
Add another language or locale
Generation profiles keep locale-specific case construction, rendering, review,
resources, and provenance outside the CLI. A provider returns a
meddeid_data.generation_profiles.GenerationProfile and registers it through
the meddeid.generation_profiles entry-point group:
[project.entry-points."meddeid.generation_profiles"]
fr = "example_meddeid_language_fr.generation:get_generation_profile"
The provider function receives profile_id and keyword-only version. It
returns a profile when supported and raises ValueError otherwise. A profile
must implement direct generation, two-stage case building/rendering,
deterministic review, and a hashed resource manifest scoped to the same profile
ID and version. Tests should verify deterministic output, all document types,
exact Unicode-code-point offsets, language metadata, profile inference from case
records, resource hashes, and CLI manifest provenance. The built-in en-GB
and en-US profiles are the executable conformance examples.
Create an annotation-ready dataset
No custom conversion script is required for a folder of plain UTF-8 text files or a CSV, TSV, or Parquet table. Create the project and import its first dataset in one command:
meddeid-data project create my-project notes.parquet \
--namespace hospital-study --language-profile nl-BE \
--id-column note_id --text-column note_text
The same command accepts notes.csv, notes.tsv, or a directory containing
.txt files. Install meddeid-data[parquet] for Parquet support.
For tables, every column other than the text and ID columns is copied into the
document's metadata by default. A column named metadata or metadata_json
is interpreted as an object and merged, so structured fields such as
patient, caregivers, and known_values reach inference and
post-processing intact. Control this explicitly with repeatable
--metadata-column, --metadata-json-column, or --no-metadata.
Zero-configuration table shape
A data scientist can avoid mapping options by producing these conventional columns:
source_id,text,patient_given_name,patient_family_name,caregiver_1_given_name,caregiver_1_family_name,caregiver_2_given_name,caregiver_2_family_name
n-1,Jan zag Alice en Bob,Jan,Peeters,Alice,Vermeulen,Bob,Janssens
source_id is used automatically when present. Patient names may instead use a
single patient column. Each caregiver may similarly use paired
caregiver_1_given_name / caregiver_1_family_name columns. The aliases
first_name / last_name are also accepted. If only a complete name is
available, use the explicit caregiver_1_full_name convention. A
caregivers column accepts a real list in Parquet or a JSON-array cell in
CSV. Any unrelated columns are preserved as ordinary metadata, but none are
required. No metadata_json construction is needed. A complete sample is
available as examples/zero-config-notes.csv.
Reusable mapping for an existing export
Column names do not otherwise need to follow the MedDeID schema. Put the hospital export mapping in a YAML or JSON file:
version: meddeid.import-mapping.v1
text_column: note_body
id_column: export_key
include_metadata: true
patient_given_name_column: subject_first_name
patient_family_name_column: subject_family_name
caregivers:
- given_name_column: primary_author_first_name
family_name_column: primary_author_family_name
- given_name_column: coauthor_first_name
family_name_column: coauthor_family_name
Each caregivers entry represents one person. It may instead contain
full_name_column; add delimiter to that entry only when the same source cell
contains several complete names.
Use it on the first import:
meddeid-data project create my-project notes.csv \
--namespace hospital-study --mapping-config import-mapping.yaml
MedDeID writes the normalized effective mapping to
my-project/manifests/import-mapping.json. Later exports with the same schema
reuse it automatically:
meddeid-data project import my-project next-export.csv
The effective mapping is saved even when the first import used CLI flags or only the zero-configuration conventions, so mapping remains a one-time project step. The external YAML is useful when the same hospital export schema should be reused across several projects.
Supplying a new --mapping-config replaces the saved mapping for that import;
individual CLI mapping flags override its fields. The complete example is in
examples/import-mapping.yaml.
For a one-off mapping, flags remain available, and the original columns still remain in metadata:
meddeid-data project create my-project notes.csv \
--namespace hospital-study --id-column note_id --text-column note_text \
--patient-given-name-column patient_first \
--patient-family-name-column patient_last \
--caregiver-column author_1_full_name \
--caregiver-column author_2_full_name
Use --patient-name-column patient_full_name when the patient name is stored in
one column. Full names use a best-effort comma/whitespace split, so prefer the
separate given/family options when those source columns exist. For one caregiver
column containing several names, add a literal delimiter:
meddeid-data project create my-project notes.parquet \
--namespace hospital-study --id-column note_id --text-column note_text \
--caregiver-column treating_clinicians --caregiver-delimiter ";"
The --caregiver-column flag always means a complete-name column. Repeat it for
several full-name columns, or add --caregiver-delimiter for several complete
names in one cell. Use the structured caregivers config shown above when an
existing export stores given and family names separately. Parquet list-valued
caregiver columns are also accepted directly. Arbitrary names such as author
or validator are never guessed.
Add --no-metadata if only the mapped canonical names should be retained and
the original source columns should be discarded. The mapped patient and
caregivers are still kept because they were explicitly requested.
The project keeps the source-to-document mapping and HMAC key under the
gitignored private/ directory. Canonical artifacts contain pseudonymous stable
IDs, empty span lists, imported metadata, hashes, and the selected language
profile. The command prints the exact next steps to generate local model
pre-annotations as the initial state of an ordinary annotation assignment:
meddeid batch my-project/artifacts/annotations.jsonl \
--output my-project/assignments/primary.jsonl \
--model stighellemans/meddeid-dutch-synth --device cpu
MEDDEID_ANNOTATIONS_PATH="$PWD/my-project/assignments/primary.jsonl" \
npm --prefix /path/to/meddeid-annotate run dev
The model spans in primary.jsonl are not a separate suggestion type. They are
the current spans in an assignment whose documents are still unreviewed. The
reviewer edits, deletes, and adds spans using the normal annotation controls.
For a profile without a released inference model, the CLI does not recommend the Dutch model. It instead prints the command for starting primary annotation directly from the imported empty-span artifact.
Model downloading happens during meddeid batch, not data import. After the
bundle is downloaded, inference is local and document text is not sent to a
server.
The separate lifecycle commands remain available when project initialization and import need to happen at different times:
meddeid-data project init my-project --namespace hospital-study --language-profile nl-BE
meddeid-data project import my-project path/to/txt-notes
# or: ... notes.csv --id-column note_id --text-column note_text
# or: ... notes.parquet --id-column note_id --text-column note_text
meddeid-data project package-annotation my-project reviewer-a.jsonl \
--annotation-set-id hospital-study-round-1 --annotator-id reviewer-7
meddeid-data project split my-project --seed 42 --train .8 --validation .1
Reusing the same project preserves document IDs; moving or reordering source files does not affect downstream identity.
Prepare training views
If development was reviewed as one assignment, pass it once. The command uses the project's split manifest to recover the train and validation subsets:
meddeid-data project prepare-training my-project \
--development assignments/development-reviewer-a.jsonl \
--test-gold subannotation/evaluation-bundle/benchmark.jsonl
For workflows that reviewed the two development subsets separately, the
equivalent inputs are --selection-train ... --selection-validation ....
This validates completion, canonical labels, exact split membership, and text identity before writing:
my-project/prepared/selection/{train,val,test}.jsonl
my-project/prepared/refit/{train,val,test}.jsonl
my-project/prepared/fit/{train,val,test}.jsonl
Use prepared/fit with meddeid-train fit for one-time training. The selection
test file is intentionally empty. The refit train file recombines
the complete reviewed development pool, while its test file contains only the
sealed gold set. Each directory has a checksum and lineage manifest; existing
non-empty output is never overwritten.
Development
pip install -e '.[dev]'
pytest
Licence
Code is AGPL-3.0-only. Generated datasets and incorporated resources retain the terms stated with their respective artifacts and source notices.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file meddeid_data-0.3.0.tar.gz.
File metadata
- Download URL: meddeid_data-0.3.0.tar.gz
- Upload date:
- Size: 361.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
436d4fedbee4090b1733c35a3938298c5d6b9b5d849064193a6389fd4efdf774
|
|
| MD5 |
3e57e548878632cbbe1e1236ba3d83ab
|
|
| BLAKE2b-256 |
61d594b570cb63a553afaf3abdce364e2ba98050fb83692e82748d50e486c53f
|
Provenance
The following attestation bundles were made for meddeid_data-0.3.0.tar.gz:
Publisher:
publish-python.yml on stighellemans/meddeid-data
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
meddeid_data-0.3.0.tar.gz -
Subject digest:
436d4fedbee4090b1733c35a3938298c5d6b9b5d849064193a6389fd4efdf774 - Sigstore transparency entry: 2617454986
- Sigstore integration time:
-
Permalink:
stighellemans/meddeid-data@6591c53c202b2dc9e916f24de3d9f1ebd7005ca1 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/stighellemans
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@6591c53c202b2dc9e916f24de3d9f1ebd7005ca1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file meddeid_data-0.3.0-py3-none-any.whl.
File metadata
- Download URL: meddeid_data-0.3.0-py3-none-any.whl
- Upload date:
- Size: 344.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fc0d9b61f267615ccf1d77c4ae4bfd524316ed9395044731186cf4c5341420d
|
|
| MD5 |
da72e6ddb25151502b2edb7ca38f3faf
|
|
| BLAKE2b-256 |
1c304fc9e98f6afd24800d033794f6bda73ca82eb9c9195f1e5d07c50574a0b3
|
Provenance
The following attestation bundles were made for meddeid_data-0.3.0-py3-none-any.whl:
Publisher:
publish-python.yml on stighellemans/meddeid-data
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
meddeid_data-0.3.0-py3-none-any.whl -
Subject digest:
9fc0d9b61f267615ccf1d77c4ae4bfd524316ed9395044731186cf4c5341420d - Sigstore transparency entry: 2617455076
- Sigstore integration time:
-
Permalink:
stighellemans/meddeid-data@6591c53c202b2dc9e916f24de3d9f1ebd7005ca1 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/stighellemans
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python.yml@6591c53c202b2dc9e916f24de3d9f1ebd7005ca1 -
Trigger Event:
push
-
Statement type: