The icd package for R includes ICD-10 support, sample ICD-10-CM data, and fast comorbidity calculations from ICD-10 (and ICD-9) diagnostic codes to the standard comorbidities defined in the literature by Charlson, Quan, Deyo, Elixhauser, pediatric complex chronic conditions and the US AHRQ. There are also 2018 ICD-10-CM procedure codes, and a mapping to categorize these. The sample data are from the US Transuranium and Uranium Registries where de-identified diagnoses are given for a few hundred pathology cases relating to uranium exposure.

The sample data is in the ‘long’ format, i.e., multiple rows per case

uranium_pathology[1:10, ]
#>    case icd10
#> 1     1 F17.9
#> 2     1 I21.9
#> 3     1 K75.9
#> 4     1   R55
#> 5     2 I25.1
#> 6     2 I35.8
#> 7     2 I63.9
#> 8     2   I64
#> 9     2 J43.9
#> 10    2 J84.1

We can convert the date from long to wide format easily. This is done quickly in C++, and gives reliable output with factors). It also has other features which make it work well with other functions in this package. However, you may be happier using and friends for this manipulation.

uranium_pathology %>% long_to_wide %>% head
#>   [,1]    [,2]    [,3]    [,4]    [,5]    [,6]    [,7]    [,8]   
#> 1 "F17.9" "I21.9" "K75.9" "R55"   NA      NA      NA      NA     
#> 2 "I25.1" "I35.8" "I63.9" "I64"   "J43.9" "J84.1" "K57.9" "N39.0"
#> 3 "I21.9" "I25.1" NA      NA      NA      NA      NA      NA     
#> 4 "T14.1" "X74"   NA      NA      NA      NA      NA      NA     
#> 5 "C34.9" "C77.1" "C77.2" "C78.0" "C78.7" "C79.7" "I51.7" "K57.9"
#> 6 "A16.9" "I12.9" "I21.9" "I25.1" "I25.9" "I70.0" "J45.9" "N26"

Now map these diagnoses to disease groups as defined by Quan et al:

quan_comorbidities <- comorbid(uranium_pathology, icd10_map_quan_elix)
# see the first few rows and columns:
quan_comorbidities[1:6, 3:10]
#>   Valvular  PHTN   PVD   HTN HTNcx Paralysis NeuroOther Pulmonary
#> 1    FALSE FALSE FALSE FALSE FALSE     FALSE      FALSE     FALSE
#> 2     TRUE FALSE FALSE FALSE FALSE     FALSE      FALSE      TRUE
#> 3    FALSE FALSE FALSE FALSE FALSE     FALSE      FALSE     FALSE
#> 4    FALSE FALSE FALSE FALSE FALSE     FALSE      FALSE     FALSE
#> 5    FALSE FALSE FALSE FALSE FALSE     FALSE      FALSE     FALSE
#> 6    FALSE FALSE  TRUE FALSE  TRUE     FALSE      FALSE      TRUE

The ICD-10-CM mappings are recorded a bit differently from the ICD-9-CM mappings in this package. The ICD-9 mappings included all possible permutations of child codes. Since ICD-10 codes contain letters, and are seven characters long, this became impractical. Therefore, the current mappings include only codes for the most recent update of ICD-10-CM. The code which assigns comorbidities for ICD-10 therefore doesn’t rely on all the possible codes being listed in the mappings, so it will (more slowly) search for each possible parent of the given code, up to the three digit ‘major’ (e.g. if Cholera was in the comorbidity mapping, then A0034212647 would eventually match A00)

# create trivial comorbidity map:
cholera_typhoid_map <- list(cholera = "A00", typhoid = "A01")
patients <- data.frame(patient = c("0001", "0001", "0002"), code = c("A001234567", "A01", "A019"))
comorbid(patients , map = cholera_typhoid_map)
#>      cholera typhoid
#> 0001    TRUE    TRUE
#> 0002   FALSE    TRUE

Here are the codes for hypertension with complications from Quan et al. Note that the vector has class icd10 and has the attribute icd_short_diag indicating there are no decimal point delimiters in the codes.

icd10_map_quan_elix$HTNcx
#>  [1] "I11"   "I110"  "I119"  "I12"   "I120"  "I129"  "I13"   "I130" 
#>  [9] "I131"  "I1310" "I1311" "I132"  "I15"   "I150"  "I151"  "I152" 
#> [17] "I158"  "I159" 
#> attr(,"icd_short_diag")
#> [1] TRUE
#> attr(,"class")
#> [1] "icd10"     "character"

Procedure codes

The AHRQ publishes an annually updated categorization of ICD-10-CM procedure codes into four classes, representing diagnostic and therapeutic procedures, each being either minor or major.

set.seed(1441)
pts <- data.frame(id = sample(LETTERS, 10),
                  pc = sample(icd10_pcs[["2018"]]$code, 10))
res <- icd10_comorbid(pts,
                      map = icd10_map_ahrq_pcs, 
                      icd_name = "pc",
                      return_binary = TRUE)
print(res)
#>   Minor Diagnostic Minor Therapeutic Major Diagnostic Major Therapeutic
#> J                0                 0                0                 1
#> A                0                 0                0                 1
#> Z                1                 0                0                 0
#> L                0                 1                0                 0
#> H                0                 0                0                 1
#> D                0                 1                0                 0
#> E                0                 1                0                 0
#> C                0                 0                0                 1
#> W                0                 0                0                 1
#> T                1                 0                0                 0
colSums(res)
#>  Minor Diagnostic Minor Therapeutic  Major Diagnostic Major Therapeutic 
#>                 2                 3                 0                 5

For more information on working with ICD-10 codes, see the introduction vignette, and function examples. E.g.

?comorbid
?explain