Agent Skillsmaziyarpanahi/openmed › shifting-clinical-dates

shifting-clinical-dates

GitHub

用于在OpenMed中对临床日期进行安全偏移,以符合HIPAA Safe Harbor标准。通过统一偏移量保留事件间的时间间隔,支持去标识化同时维持生存分析等纵向研究所需的时序结构。

skills/shifting-clinical-dates/SKILL.md maziyarpanahi/openmed

触发场景

需要脱敏临床日期但保留时间间隔 执行HIPAA合规的去标识化处理 生成可复现的患者级日期偏移

安装

npx skills add maziyarpanahi/openmed --skill shifting-clinical-dates -g -y
更多选项

不安装直接使用

npx skills use maziyarpanahi/openmed@shifting-clinical-dates

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill shifting-clinical-dates -a claude-code -g -y

安装 repo 全部 skill

npx skills add maziyarpanahi/openmed --all -g -y

预览 repo 内 skill

npx skills add maziyarpanahi/openmed --list

SKILL.md

Frontmatter
{
    "name": "shifting-clinical-dates",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "after",
        "project": "OpenMed",
        "version": "1.0",
        "category": "de-identification"
    },
    "description": "Apply consistent per-patient date shifting in OpenMed that preserves intervals between events while satisfying HIPAA Safe Harbor's date rule. Use when the user needs to de-identify dates but keep temporal structure for research, shift all dates by the same offset per patient, preserve days-between-events for survival or longitudinal analysis, cap ages over 89, or strip everything but the year. Covers deidentify(method=\"shift_dates\", date_shift_days=..., keep_year=...) and per-patient reproducible offsets via consistent=True, seed=.... Pairs with OpenMed deidentifying-clinical-text and auditing-safe-harbor-checklist."
}

Shifting clinical dates

HIPAA Safe Harbor forbids keeping dates more specific than the year. But naively deleting dates destroys the temporal structure research depends on — time to event, length of stay, intervals between visits. Date shifting is the compromise: move every date by a single random offset so the absolute dates become meaningless while the intervals between them are preserved exactly. OpenMed does this on-device with deidentify(method="shift_dates", ...).

When to use this skill

Use it when downstream analysis needs temporal relationships (survival curves, sepsis-to-antibiotic time, readmission gaps) but the calendar dates must be de-identified. If you can throw dates away entirely, plain method="mask" is simpler — reach for shifting only when intervals matter.

Quick start

import openmed

note = (
    "Admitted 2024-03-02, started antibiotics 2024-03-04, discharged 2024-03-09. "
    "Follow-up scheduled 2024-04-02."
)

# Shift every date by the SAME offset -> intervals preserved, dates obscured.
result = openmed.deidentify(
    note,
    method="shift_dates",
    consistent=True,        # one stable offset for this run
    seed=20240519,          # reproducible per-patient offset (use a per-patient key)
    keep_year=False,        # do NOT retain the year (Safe Harbor: year-only is the max)
)
print(result.deidentified_text)
# Admit -> antibiotics is still 2 days; admit -> discharge still 7 days; etc.

How interval preservation works

All dates in the document are moved by one offset (auto-selected as a random non-zero value in roughly ±1 year, or fixed with date_shift_days=). Because the offset is identical for every date, the difference between any two dates is unchanged:

real:    Mar 2  ──2d──▶ Mar 4  ──5d──▶ Mar 9
shifted: Jul 18 ──2d──▶ Jul 20 ──5d──▶ Jul 25     (offset = +138 days, intervals intact)

That is why survival time, length of stay, and visit gaps survive de-identification while the actual calendar is destroyed.

Per-patient consistent offsets

Each patient should get their own offset, and that offset should be stable across documents and reproducible across runs. Derive a per-patient seed (e.g. from a secret keyed hash of the patient ID — never the raw MRN) and pass it as seed=:

def patient_offset_seed(patient_key: str) -> int:
    import hashlib, hmac
    # keyed so the mapping from patient -> offset is itself a secret
    digest = hmac.new(b"<vault-secret>", patient_key.encode(), hashlib.sha256).digest()
    return int.from_bytes(digest[:8], "big")

for doc in patient_documents:
    openmed.deidentify(
        doc, method="shift_dates",
        consistent=True, seed=patient_offset_seed(patient_id),
        keep_year=False,
    )

Same patient → same offset everywhere (their notes stay internally consistent); different patients → different offsets (cross-patient dates cannot be aligned).

Workflow

  1. Decide the offset policy. Per-patient is standard for clinical research. Use consistent=True + a per-patient seed. Use a fixed date_shift_days= only when a deterministic, externally-managed offset is required.
  2. Set keep_year=False for Safe Harbor. (keep_year=True retains the year, which is permissible only if dates aren't tied to an individual's care.)
  3. Cap ages over 89 separately. Date shifting moves dates; it does not aggregate ages. Safe Harbor requires ages >89 and any date implying age >89 to collapse to a single "90+" — handle AGE spans explicitly (auditing-safe-harbor-checklist).
  4. Keep names/IDs handled too. shift_dates only touches dates. Run a normal redaction pass (or a policy) for PERSON, ID_NUM, etc.
  5. Verify intervals are preserved and no calendar leaked via audit=True.

Hand-off to / from OpenMed

  • Core de-id: deidentifying-clinical-text — combine date shifting with a policy= so names/IDs are redacted in the same pipeline.
  • Safe Harbor checklist: auditing-safe-harbor-checklist — the date rule and the age-90 cap are categories C in the 18.
  • Audit: auditing-deidentification-runs records the method and per-span actions (offsets/hashes, not raw dates).
  • Other surfaces: MCP openmed_deidentify / REST POST /pii/deidentify accept the same method and parameters.

Edge cases & gotchas

  • Offset 0 is forbidden. An auto-selected offset is always non-zero — a zero shift would silently leave dates unchanged and defeat de-identification.
  • Reuse the seed per patient, not globally. A single global offset lets an attacker re-align all patients to a real anchor date; per-patient offsets break that. Derive seeds from a secret, not the plaintext MRN.
  • keep_year=True is not Safe Harbor by itself when the year reveals the age of someone >89 or ties to care episodes — pair with age capping.
  • Shifting does not cap ages. Age >89 is a separate transformation; date shifting won't fix an explicit "age 94" in the text.
  • Day-first locales. For non-English notes set lang= so 11/04/2024 is parsed in the right order before shifting (deidentifying-multilingual-text).
  • Store the per-patient seed/offset like PHI — it re-identifies the calendar if leaked. Keep it in a vault, separate from the output.

Standards & references

版本历史

  • f213557 当前 2026-07-23 00:46

同 Skill 集合

skills/benchmark-pii-recall/SKILL.md
skills/building-with-openmed/SKILL.md
skills/deidentify-a-dataset/SKILL.md
skills/extract-clinical-entities-to-fhir/SKILL.md
skills/loading-openmed-models/SKILL.md
skills/pick-a-pii-model/SKILL.md
skills/annotating-variants/SKILL.md
skills/assembling-fhir-bundles/SKILL.md
skills/auditing-deid-leakage/SKILL.md
skills/auditing-deidentification-runs/SKILL.md
skills/auditing-part11-trails/SKILL.md
skills/auditing-safe-harbor-checklist/SKILL.md
skills/auditing-subgroup-fairness/SKILL.md
skills/authoring-model-cards/SKILL.md
skills/batch-processing-clinical-text/SKILL.md
skills/benchmarking-clinical-ner/SKILL.md
skills/bridging-presidio-and-spacy/SKILL.md
skills/building-gold-corpus/SKILL.md
skills/building-patient-timelines/SKILL.md
skills/checking-hipaa-compliance/SKILL.md
skills/choosing-openmed-models/SKILL.md
skills/coding-hcc-risk-adjustment/SKILL.md
skills/coding-icd10/SKILL.md
skills/computing-ecqms/SKILL.md
skills/configuring-privacy-policies/SKILL.md
skills/defining-cohort-phenotypes/SKILL.md
skills/deidentifying-clinical-text/SKILL.md
skills/deidentifying-multilingual-text/SKILL.md
skills/deploying-openmed-mcp/SKILL.md
skills/detecting-pv-signals/SKILL.md
skills/enforcing-nophi-logging/SKILL.md
skills/etl-to-omop-cdm/SKILL.md
skills/evaluating-with-leakage-gates/SKILL.md
skills/exporting-bulk-fhir/SKILL.md
skills/exporting-to-fhir/SKILL.md
skills/extracting-clinical-entities/SKILL.md
skills/extracting-dicom-metadata/SKILL.md
skills/extracting-lab-tables/SKILL.md
skills/extracting-pii-entities/SKILL.md
skills/extracting-sdoh/SKILL.md
skills/fetching-fhir-resources/SKILL.md
skills/gating-deid-leakage/SKILL.md
skills/generating-synthea-data/SKILL.md
skills/generating-synthetic-surrogates/SKILL.md
skills/ingesting-clinical-documents/SKILL.md
skills/linking-umls-concepts/SKILL.md
skills/mapping-loinc/SKILL.md
skills/mapping-to-snomed/SKILL.md
skills/mining-pubmed-literature/SKILL.md
skills/normalizing-rxnorm/SKILL.md

元信息

文件数
0
版本
de90aba
Hash
3dcd6e73
收录时间
2026-07-23 00:46

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-04 08:10
浙ICP备14020137号-1 $访客地图$