General Equivalence Mappings
CMS General Equivalence Mappings (GEMs) describe relationships between ICD-9-CM and ICD-10. They are not one-to-one conversion tables: a source can have no target, several alternatives, or a combination of targets that must be interpreted together.
cms-icd therefore exposes every official row and flag. It deliberately does not pick
a preferred target. Applications remain responsible for that policy.
from cms_icd import GEMKnowledgeBase
gems = GEMKnowledgeBase.from_cms(
fiscal_year=2018,
cache_dir="cache/cms_icd",
)
entries = gems.cm.icd9_to_icd10["4280"]
for entry in entries:
print(entry.target, entry.approximate, entry.scenario, entry.choice_list)
For structured alternatives and combinations, request the grouped mapping:
mapping = gems.cm.icd9_to_icd10.mapping("4280")
for scenario in mapping.scenarios:
for choice_list in scenario.choice_lists:
print([entry.target for entry in choice_list.alternatives])
Simple alternatives are OR relationships. Scenarios are OR relationships, choice lists inside one scenario are AND relationships, and alternatives inside one choice list are OR relationships. A mapping may contain both simple and combination entries; the library exposes both and does not impose a resolution policy.
Diagnosis mappings are available through gems.cm; procedure mappings are available
through gems.pcs. Each view provides icd9_to_icd10 and icd10_to_icd9 stores. The
requested system and direction are downloaded and parsed only when accessed.
Flags and no-map rows
Each GEMEntry contains:
sourceand nullabletargetcode strings, with leading zeroes preserved;approximate,no_map, andcombinationboolean flags;- numeric
scenarioandchoice_listidentifiers.
When CMS uses NoDx in CM files, NoPCS in forward PCS files, or NoI9 in reverse PCS
files, target is None and no_map is true. Multiple entries for a source are returned
as an immutable tuple in deterministic scenario/choice/target order. A few official
reverse PCS releases omit the no-map flag on NoI9 rows; the parser treats the sentinel
as authoritative and normalizes those rows to no_map=True.
Reproducible and offline use
Select a fiscal year explicitly; GEMs are fiscal-year artifacts and do not use the
intra-year snapshot selection of ICD-10 tabular files. After an online run has populated
the catalog and artifact cache, require cache-only operation with offline=True:
Offline mode never contacts CMS and raises DownloadError with the missing cache
requirement. For externally managed files, use
GEMKnowledgeBase.from_directory(directory, fiscal_year=2018) with the original CMS
filenames intact.
GEMs are distinct from reimbursement mappings and other conversion tables. Catalog discovery excludes those artifacts.
Exact and retrospectively corrected history
from_cms() returns the official rows for one fiscal year without modification.
corrected_from_cms() retains that fiscal year's target-code vocabulary while adopting
later correction-only complete row sets:
corrected = GEMKnowledgeBase.corrected_from_cms(
fiscal_year=2016,
cache_dir="cache/cms_icd",
)
store = corrected.cm.icd9_to_icd10
entries = store["27906"]
lineage = store.provenance("27906")
Procedure mappings use the same release selection and provenance contract:
pcs_store = corrected.pcs.icd9_to_icd10
pcs_mapping = pcs_store.mapping("0001")
pcs_lineage = pcs_store.provenance("0001")
ICD10_PCS_CHARACTERS exposes the ordered, release-stable PCS alphabet for consumers
that represent the seven code axes independently. It excludes the ambiguous letters
I and O.
The algorithm compares consecutive official releases and their opposite-direction code universes. It stops a source at the first transition involving an introduced or retired source/target code. Mixed lifecycle and correction changes are not partially applied, and processing does not resume for that source after the boundary. Consequently, every result is a complete row set copied from one official release rather than a filtered or synthetic cluster.
The correction horizon defaults to FY2018, the final CMS GEM release. Pass
corrections_through_fiscal_year only when a deliberately narrower review horizon is
required.
GEMProvenance records the historical vocabulary release, the release supplying the
selected rows, the pinned review horizon, and the first lifecycle boundary when one was
encountered. Missing intermediate releases remain errors; there is no silent fallback.
Bulk best-effort resolution
Applications that need complete conversion tables up front can resolve several historical vocabularies in one request:
from cms_icd import (
resolve_icd9_to_icd10_cm_mappings,
resolve_icd9_to_icd10_pcs_mappings,
)
years = range(2014, 2019)
diagnoses = resolve_icd9_to_icd10_cm_mappings(years)
procedures = resolve_icd9_to_icd10_pcs_mappings(years)
diagnosis_targets = diagnoses[2016]["4280"].target_codes
procedure_patterns = procedures[2016]["0001"].target_patterns
The outer mappings are keyed by fiscal year and the inner mappings by ICD-9
source code. Both levels are immutable. Passing fiscal_years=None, the
default, discovers every compatible advertised GEM year through the pinned
FY2018 correction horizon. Pass explicit years when a cohort must remain fixed.
The resolver applies a deterministic best-effort policy; it is not an authoritative one-to-one clinical conversion:
- a single official target is retained, including its approximate flag;
- diagnosis alternatives are reduced to their lowest usable ICD-10-CM common ancestor when one exists;
- complete combination mappings retain every required target and its order;
- procedure alternatives retain shared axes and use
?where later axes disagree; - incompatible alternatives, invalid targets, and official no-map rows return
an
unmappablestatus with empty targets.
Every resolution includes a reason and the corrected GEM provenance. Unknown
source codes are absent from the mapping; callers choose their own missing-code
fallback. The singular resolve_icd9_to_icd10_cm_mapping() and
resolve_icd9_to_icd10_pcs_mapping() functions provide the same result for one
fiscal year through the bulk loader.