agentsclimarketplace

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.

Install
npx -y skills add rbr7/MedClawMini --skill patient-record-entity-resolution

Assembled 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.

  1. Standardize fields first (names, addresses via usaddress, dates, phone, gender); normalize provider IDs and run medical-ontology-code-mapping for any coded fields.
  2. Block to avoid the O(n²) all-pairs blow-up: index candidate pairs by cheap keys (e.g., soundex(last_name) + dob_year, or zip + first_initial). Critical at scale.
  3. Compare within blocks using Jaro-Winkler / Levenshtein / token-set similarity per field; handle nulls explicitly.
  4. Score pairs with the Fellegi-Sunter weights (Splink learns m/u via EM, so no labeled data is strictly required).
  5. Cluster matched pairs into entities (connected components / graph resolution) and review the borderline band manually or with active learning.
  6. 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.parquet source row → resolved entity_id.
  • golden_records.parquet one survivorship record per entity with lineage.
  • match_pairs.parquet scored pairs with per-field contributions (explainable).
  • linkage_report.md blocking 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

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.