Patient record entity resolution
Skill rbr7/MedClawMini/skills/patient-record-entity-resolution
A focused, production-minded library of 197 clinical-AI and healthcare data-science skills for the OpenClaw agent platform featuring data quality, clinical NLP, big-data ML, explainable AI, drug safety, and regulatory.
npx -y skills add rbr7/MedClawMini --skill patient-record-entity-resolutionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Resolve, link, and deduplicate healthcare entity records patients/members, providers, and facilities across messy, inconsistent sources. Covers blocking/indexing, deterministic and probabilistic (Fellegi-Sunter) matching, fuzzy string similarity, the Splink/recordlinkage/dedupe toolchain, match-threshold tuning, and survivorship rules to build a "golden record." Use for master patient index (MPI/EMPI) work, provider-roster deduplication, NPI/member crosswalks, or any record-linkage / entity-resolution task.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
5.5 KB, as published. Nobody here has run it
Patient & Provider Entity Resolution
Overview
The same patient, provider, or facility appears many times across claims, eligibility, and clinical systems under slightly different names, addresses, and IDs. This skill links those records into a single resolved entity and produces a golden record. It implements the full entity-resolution pipeline blocking, comparison, probabilistic scoring, clustering, and survivorship using production-grade open-source tooling.
When to Use This Skill
- Building or cleaning a Master Patient Index (MPI/EMPI) or provider master.
- Deduplicating a member or provider roster before analytics or capitation payment.
- Crosswalking entities across payers/vendors that lack a shared key.
- Reducing "duplicate patient" safety risks or double-counting in reporting.
- Any general record linkage / entity resolution problem on tabular data.
Method
The core is the Fellegi–Sunter probabilistic model: for each candidate pair, combine
field-level agreement/disagreement into a match weight using learned m and u
probabilities, then threshold into match / possible-match / non-match.
- Standardize fields first (names, addresses via
usaddress, dates, phone, gender); normalize provider IDs and runmedical-ontology-code-mappingfor any coded fields. - Block to avoid the O(n²) all-pairs blow-up: index candidate pairs by cheap keys
(e.g.,
soundex(last_name) + dob_year, orzip + first_initial). Critical at scale. - Compare within blocks using Jaro-Winkler / Levenshtein / token-set similarity per field; handle nulls explicitly.
- Score pairs with the Fellegi-Sunter weights (Splink learns
m/uvia EM, so no labeled data is strictly required). - Cluster matched pairs into entities (connected components / graph resolution) and review the borderline band manually or with active learning.
- Survivorship build the golden record per cluster (most-recent, most-complete, or source-priority rules) and keep full lineage back to source rows.
Example
# Probabilistic linkage with Splink (DuckDB backend) scales to millions of rows
from splink.duckdb.linker import DuckDBLinker
import splink.duckdb.comparison_library as cl
settings = {
"link_type": "dedupe_only",
"blocking_rules_to_generate_predictions": [
"l.dob = r.dob and substr(l.last_name,1,1) = substr(r.last_name,1,1)",
"l.zip = r.zip",
],
"comparisons": [
cl.jaro_winkler_at_thresholds("first_name", [0.9, 0.7]),
cl.jaro_winkler_at_thresholds("last_name", [0.9, 0.7]),
cl.exact_match("dob"),
cl.levenshtein_at_thresholds("address", 2),
],
}
linker = DuckDBLinker(df, settings)
linker.estimate_u_using_random_sampling(max_pairs=1e6)
linker.estimate_parameters_using_expectation_maximisation(
"l.dob = r.dob and l.last_name = r.last_name")
pairs = linker.predict(threshold_match_probability=0.95)
clusters = linker.cluster_pairwise_predictions_at_threshold(pairs, 0.95)
# Lightweight alternative for small data: recordlinkage
import recordlinkage as rl
idx = rl.Index(); idx.block("dob_year")
cand = idx.index(df)
cmp = rl.Compare()
cmp.string("last_name","last_name", method="jarowinkler", threshold=0.85, label="ln")
cmp.exact("dob","dob", label="dob")
features = cmp.compute(cand, df)
matches = features[features.sum(axis=1) >= 2]
Evaluation
Report precision, recall, and F1 against a labeled gold set when available; otherwise use clerical review of a sampled borderline band. Track the match-rate and duplicate-collapse rate, and always expose a tunable threshold so reviewers can trade precision vs. recall (false-merge of two real patients is a safety event bias toward precision and route ambiguous pairs to review).
Outputs
entity_clusters.parquetsource row → resolvedentity_id.golden_records.parquetone survivorship record per entity with lineage.match_pairs.parquetscored pairs with per-field contributions (explainable).linkage_report.mdblocking stats, score distribution, threshold, P/R/F1.
Healthcare Context
Optimized for patient/member and provider/NPI matching, including the hard cases:
nicknames, maiden/married names, twins sharing an address, transposed DOBs, and group-vs-
individual NPIs. Upstream: healthcare-data-quality-profiling. Pairs with
spark-healthcare-data-pipeline for billion-row deployment.
References
- Splink (UK MoJ) https://moj-analytical-services.github.io/splink/
- Python Record Linkage Toolkit https://recordlinkage.readthedocs.io
- Fellegi, I. & Sunter, A. (1969), A Theory for Record Linkage, JASA.