Python pipeline for validating and map structured outputs extracted from unstructured clinical notes using biomedical APIs and ontologies.
The project validates three types of extracted clinical entities:
- Genes using the HGNC REST API.
- HGVS variant descriptions using the Mutalyzer API.
- Patient-data keywords using the OLS4 API to retrieve matching ontology terms.
For each clinical note, the pipeline:
- Reads the structured JSON output.
- Validates gene symbols against HGNC.
- Validates HGVS descriptions with Mutalyzer.
- Maps patient-data keywords to ontology terms using OLS4.
- Creates a validated output JSON file.
- Creates a separate error summary JSON file.
Clone the repository:
git clone https://github.com/your-username/clinical-note-ontology-validation.git
cd clinical-note-ontology-validationPython 3.5 or later is needed. The script depends on standard libraries, plus the ones declared in requirements.txt.
Using a virtual environment is recommended:
python3 -m venv .env
source .env/bin/activate
pip install --upgrade pip
pip install -r requirements.txtRun the pipeline from the command line:
python main.py input.json validated_output.json validation_errors.jsonWhere:
input.json: Input file with structured clinical-note data.validated_output.json: Output file containing the original data plus validation results and mapping to ontologies.validation_errors.json: Output file containing entities that could not be validated.
If you want to test the program, use test/example_input.json as input file.
The configuration file config.py contains API URLs and general settings used across the project.
The ontology mapper is configured with the ONTOLOGY_VALIDATION_FIELDS variable.
Each configuration item defines:
json_property: the property name in the JSON input.ontology: the OLS ontology identifier used to validate values from that field.
Example:
ONTOLOGY_VALIDATION_FIELDS = [
{
"json_property": "symptoms",
"ontology": "hp"
},
{
"json_property": "sex",
"ontology": "ncit"
}
]This means:
- values in
symptomsare validated against HPO (hp), - values in
sexare validated against NCIT (ncit).
To validate another JSON property, add a new dictionary to ONTOLOGY_VALIDATION_FIELDS.
Example:
ONTOLOGY_VALIDATION_FIELDS = [
{
"json_property": "disease",
"ontology": "ordo"
}
]The input file must be a JSON file containing a list of clinical-note records.
Each record must contain the following data elements:
- `id`: Identifier of the subject or clinical note.
- `unstructuredData`: Original unstructured clinical note.
- `structuredData`: List containing the extracted structured fields.
Example from test/example_input.json:
[
{
"id": 1,
"unstructuredData": "Test clinical note with genetic data as RFC1, and mutation NG_012232.1(NM_004006.2):c.93+1G>T; Symptoms are Diplopia and Oscillopsia",
"structuredData": [
{
"geneticDiagnosis": [
"RFC1",
"testGene"
],
"HGVS": [
"NG_012232.1(NM_004006.2):c.93+1G>T",
"test",
"NT_012232.1(NM_004006.2):c.93+1G>Z"
],
"symptoms": [
"Diplopia",
"Oscillopsia",
"Oscillopsie",
"Test Data"
],
"sex":["Male"]
}
]
}
]The pipeline validates three groups of structured data:
Gene symbols are validated against HGNC. Name of property must be geneticDiagnosis.
Example field:
"geneticDiagnosis": [
"RFC1"
]HGVS variant descriptions are validated with Mutalyzer. Name of property must be HGVS.
Example field:
"HGVS": [
"NG_012232.1(NM_004006.2):c.93+1G>T"
]Any field listed in ONTOLOGY_VALIDATION_FIELDS from the config.py file is validated with OLS4.
Example field:
"sex": [
"Male"
]The script creates two output files.
This file contains the original clinical note data with an added ontologyData section.
Example:
"ontologyData": {
"geneticDiagnosis": [...],
"HGVS": [...],
"ontologyFields": {
"symptoms": [...],
"sex": [...],
.
.
.
}
}{
"gene": "RFC1",
"valid": true,
"HGNCId": "HGNC:9969",
"approvedSymbol": "RFC1",
"geneName": "replication factor C subunit 1",
"status": "Approved",
"matchType": "approved_symbol"
}{
"input": "NM_000059.4:c.7790G>A",
"structurallyValid": true,
"apiValid": true,
"normalizedDescription": "NM_000059.4:c.7790G>A",
"errors": []
}{
"keyword": "Male",
"ontology": "ncit",
"valid": true,
"IRI": "http://purl.obolibrary.org/obo/NCIT_C20197",
"ontologyId": "NCIT:C20197",
"label": "Male",
"ontologyName": "ncit",
"matchType": "exact_search",
"score": null,
"synonyms": [
"Human, Male",
"M",
"MALE",
"Male",
"male"
]
}This file summarizes entities that could not be validated.
Example structure:
{
"unknownGenes": [],
"invalidHGVS": [],
"unknownOntologyTerms": []
}Each item in unknownOntologyTerms includes the original JSON property so that failed mappings can be traced back to the configured input field.
The gene validator first checks whether the input is an approved HGNC symbol. If no result is found, it checks previous symbols and aliases. This improves validation for clinical notes that may contain older gene names or alternative symbols.
The HGVS validator uses a basic regular expression before calling Mutalyzer. This avoids unnecessary API calls for clearly invalid strings. However, the regular expression is not a complete HGVS grammar validator.
The ontology validator first performs an exact search against ontology labels and synonyms in OLS4 search endpoint. If no exact result is found, it can use the OLS4 LLM search endpoint as a fallback. Semantic matches should be reviewed carefully, especially in clinical or research settings.
- The pipeline validates extracted structured data but does not perform the original text extraction from clinical notes.
- The HGVS local check only validates the basic format.
- API results may change over time depending on updates in HGNC, Mutalyzer or/and OLS4.
- The semantic ontology fallback may return broad or imperfect matches.
- Manual review is recommended for uncertain or low-confidence mappings.
- The current pipeline assumes that the relevant extracted data are available inside the first item of
structuredData.
Sergi Aguiló Castillo, Data Steward, Medical Biosciences Dpt., Radboudumc - ORCID