Run clinical and biomedical named-entity recognition on medical text with OpenMed's analyze_text. Use when the user wants to extract diseases, drugs, anatomy, genes, or other biomedical entities from notes; needs NER output as dict/json/html/csv; wants to filter by confidence, group entities, toggle sentence detection, or save spans to JSONL; or wants the openmed analyze CLI. Pairs with loading-openmed-models and choosing-openmed-models, and runs after deidentifying-clinical-text in a privacy...
Scanned 9/12/2026
Install to Claude Code
npx -y skills add maziyarpanahi/openmed --skill extracting-clinical-entities --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Extracting Clinical Entities?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/maziyarpanahi-extracting-clinical-entities)More formats (shields.io, HTML) on the badges page.
---
name: extracting-clinical-entities
description: "Run clinical and biomedical named-entity recognition on medical text with OpenMed's analyze_text. Use when the user wants to extract diseases, drugs, anatomy, genes, or other biomedical entities from notes; needs NER output as dict/json/html/csv; wants to filter by confidence, group entities, toggle sentence detection, or save spans to JSONL; or wants the openmed analyze CLI. Pairs with loading-openmed-models and choosing-openmed-models, and runs after deidentifying-clinical-text in a privacy-first pipeline."
license: Apache-2.0
metadata:
project: OpenMed
category: openmed-core
pairs: adjacent
version: "1.0"
---
# Extracting Clinical Entities
`openmed.analyze_text` runs a token-classification model over medical text and
returns structured entities with character offsets and confidence scores. It runs
**on-device** after a one-time model download.
## When to use
- Pull diseases, medications, anatomy, genes, proteins, etc. out of clinical text.
- You need exact **character spans** (start/end) plus **confidence** per entity.
- You want output as objects, JSON, an HTML highlight view, or CSV.
- You are building the "extract entities" stage of a clinical NLP pipeline.
To choose a model, see `choosing-openmed-models`. To load it once and reuse it,
see `loading-openmed-models`. **In a PHI workflow, de-identify first** (see
`deidentifying-clinical-text`), then run NER on the redacted text.
## Install
```bash
pip install "openmed[hf]"
```
## Quick start
```python
import openmed
note = (
"Patient prescribed 500 mg metformin for type 2 diabetes mellitus. "
"Reports intermittent chest pain; ruled out myocardial infarction."
)
result = openmed.analyze_text(
note,
model_name="disease_detection_superclinical", # registry key, HF id, or local path
output_format="dict", # dict | json | html | csv
confidence_threshold=0.5,
)
for ent in result.entities:
print(f"{ent.label:12} {ent.text!r:40} {ent.confidence:.2f} [{ent.start}:{ent.end}]")
```
With `output_format="dict"` you get a `PredictionResult`. The fields you use most:
```text
result.text # the original input text
result.entities # list of entity objects
result.model_name # which model produced these
ent.text # the surface string
ent.label # entity type, e.g. "DISEASE"
ent.confidence # model score in [0, 1] (NOTE: .confidence, not .score)
ent.start / ent.end # character offsets into result.text
```
## Output formats
`analyze_text(...)` returns different types depending on `output_format`:
| `output_format` | Return type | Use for |
| --- | --- | --- |
| `"dict"` (default) | `PredictionResult` object | Programmatic access via `.entities`. |
| `"json"` | `str` (JSON) | Logging, APIs, writing to disk. |
| `"html"` | `str` (HTML) | A highlighted preview of the note. |
| `"csv"` | `str` (CSV) | Spreadsheet / quick review. |
```python
import openmed
note = "Started atorvastatin 40 mg; history of myocardial infarction."
json_str = openmed.analyze_text(note, output_format="json")
html_str = openmed.analyze_text(note, output_format="html") # render in a browser
csv_str = openmed.analyze_text(note, output_format="csv")
```
## Key parameters
```python
openmed.analyze_text(
text,
model_name="disease_detection_superclinical",
output_format="dict",
confidence_threshold=0.5, # drop entities below this score; None keeps all
aggregation_strategy="simple", # HF subword aggregation; None for raw tokens
group_entities=False, # merge adjacent same-label spans into one
include_confidence=True, # include scores in formatted output
sentence_detection=True, # pySBD sentence splitting (better long-doc spans)
sentence_language="en",
loader=None, # pass a reused ModelLoader (see loading skill)
)
```
- **`confidence_threshold`** — the most useful knob. Use the model's
`recommended_confidence` (from `get_model_info`) as a starting point.
- **`group_entities=True`** — merges `"type"`, `"2"`, `"diabetes"` fragments into a
single `"type 2 diabetes"` span. Turn on for cleaner output.
- **`sentence_detection=True`** (default) — splits long notes into sentences before
inference for more accurate offsets and to respect model max length. Requires
pySBD; if unavailable it silently falls back to whole-text inference.
## Save results to JSONL
One line per note keeps offsets and labels for downstream grounding or eval:
```python
import json
import openmed
notes = [
"Type 2 diabetes managed with metformin.",
"Acute myocardial infarction; started aspirin and atorvastatin.",
]
with open("entities.jsonl", "w", encoding="utf-8") as fh:
for i, note in enumerate(notes):
result = openmed.analyze_text(note, output_format="dict")
fh.write(json.dumps({
"doc_id": i,
"text": result.text,
"model": result.model_name,
"entities": [
{"label": e.label, "text": e.text,
"start": e.start, "end": e.end,
"confidence": round(e.confidence, 4)}
for e in result.entities
],
}) + "\n")
```
Store **offsets and labels**, not extra copies of free text, in PHI contexts.
## CLI
```bash
openmed analyze --text "Type 2 diabetes managed with metformin." \
--model disease_detection_superclinical \
--format json \
--threshold 0.5 \
--group
# Or analyze a file:
openmed analyze --input-file note.txt --model disease_detection_superclinical -o csv
```
Flags: `--text/-t`, `--input-file/-f`, `--model/-m`, `--format/-o`
(`dict|json|html|csv`), `--threshold/-c`, `--group`, `--no-confidence`,
`--sentence-detection/--no-sentence-detection`.
## Hand-off to / from OpenMed
- **From `loading-openmed-models`:** pass your reused `loader=` so a batch loads
weights once.
- **From `deidentifying-clinical-text`:** run NER on `result.deidentified_text`,
not raw PHI:
```python
deid = openmed.deidentify(raw_note, method="mask", policy="hipaa_safe_harbor")
ner = openmed.analyze_text(deid.deidentified_text, output_format="dict")
```
- **To terminology grounding (out-of-process):** map `ent.text`/`ent.label` to
RxNorm / LOINC / SNOMED using the user's own licensed service — OpenMed does not
bundle restricted terminologies.
- **To batch processing:** for large corpora use `openmed.process_batch(...)` /
`BatchProcessor` (see processing utilities) with a shared loader.
## Edge cases & gotchas
- **Attribute is `.confidence`, not `.score`.** Entity objects extend
`EntityPrediction` (`text`, `label`, `confidence`, `start`, `end`).
- **Right model for the labels.** A Disease model won't emit oncology staging or
gene labels — pick the category in `choosing-openmed-models` and check
`entity_types`.
- **Offsets index `result.text`.** Slice the original string with `start:end`; the
surface form in `ent.text` is whitespace-trimmed.
- **Long documents:** keep `sentence_detection=True` so chunks respect the model's
max length (`get_model_max_length`); disabling it can truncate long notes.
- **NER assists, it does not diagnose.** Treat output as decision support; surface
a disclaimer for any clinical-facing use.
- **No raw PHI in logs.** Log labels, offsets, and hashes — never patient text.
## Standards & references
- Token classification / NER (Hugging Face):
https://huggingface.co/docs/transformers/tasks/token_classification
- pySBD sentence boundary detection: https://github.com/nipunsadvilkar/pySBD
- OpenMed model cards: https://huggingface.co/OpenMed
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!