Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculate Medicare Hierarchical Condition Categories HCC #87

Merged
merged 24 commits into from
Aug 31, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Description: Calculate comorbidities, Charlson scores, perform fast and accurate
from Quan (Deyo and Elixhauser versions), Elixhauser and AHRQ included. This
package replaces 'icd9', which can now be uninstalled.
Classification/ACM-2012: Social and professional topics~Medical records, Applied computing~Health care information systems, Applied computing~Health informatics, Applied computing~Bioinformatics
Version: 2.0.1
Version: 2.0.1.9000
Date: 2016-04-10
Authors@R: c(
person(given = "Jack O.", family = "Wasey", role = c("aut", "cre", "cph"), email = "jack@jackwasey.com"),
Expand Down
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export(as.icd_wide_data)
export(icd10_comorbid)
export(icd10_comorbid_ahrq)
export(icd10_comorbid_elix)
export(icd10_comorbid_hcc)
export(icd10_comorbid_quan_deyo)
export(icd10_comorbid_quan_elix)
export(icd10_filter_invalid)
Expand Down Expand Up @@ -208,6 +209,7 @@ export(icd9WideToLong)
export(icd9_comorbid)
export(icd9_comorbid_ahrq)
export(icd9_comorbid_elix)
export(icd9_comorbid_hcc)
export(icd9_comorbid_quan_deyo)
export(icd9_comorbid_quan_elix)
export(icd9_filter_invalid)
Expand All @@ -222,6 +224,7 @@ export(icd_comorbid)
export(icd_comorbid_ahrq)
export(icd_comorbid_df_to_mat)
export(icd_comorbid_elix)
export(icd_comorbid_hcc)
export(icd_comorbid_mat_to_df)
export(icd_comorbid_quan_deyo)
export(icd_comorbid_quan_elix)
Expand Down
176 changes: 176 additions & 0 deletions R/comorbid.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ icd9PoaChoices <- icd_poa_choices
#' pts <- icd_long_data(visit_name = c("2", "1", "2", "3", "3"),
#' icd9 = c("39891", "40110", "09322", "41514", "39891"))
#' icd_comorbid(pts, icd9_map_ahrq, short_code = TRUE) # visit_name is now sorted
#' pts <- icd_long_data(
#' visit_name = c("1", "2", "3", "4", "4"),
#' icd_name = c("20084", "1742", "30410", "41514", "95893"),
#' date = as.Date(c("2011-01-01", "2011-01-02", "2011-01-03",
#' "2011-01-04", "2011-01-04")))
#' pt_hccs <- icd_comorbid_hcc(pts, date_name = "date")

#' @export
icd_comorbid <- function(x, map, ...) {
ver <- icd_guess_version.character(map[[1]])
Expand Down Expand Up @@ -588,6 +595,152 @@ icd10_comorbid_quan_deyo <- function(x, ..., abbrev_names = TRUE, hierarchy = TR
apply_hier_quan_deyo(cbd, abbrev_names = abbrev_names, hierarchy = hierarchy)
}

#' @rdname icd_comorbid
#' @export
icd9_comorbid_hcc <- function(x,
date_name = "date",
visit_name = NULL,
icd_name = NULL
) {
assert_data_frame(x, min.cols = 3, col.names = "unique")
assert(checkString(visit_name), checkNull(visit_name))
assert(checkString(icd_name), checkNull(icd_name))
visit_name <- get_visit_name(x, visit_name)
icd_name <- get_icd_name(x, icd_name)
assert_string(date_name)
assert_string(visit_name)
assert_string(icd_name)

icd_map <- icd::icd9_map_cc
# Add column for year
x$year <- as.numeric(format(x[[date_name]], "%Y"))

# merge CCs to patient data based on ICD and year drop ICD info
x <- merge(x, icd::icd9_map_cc, all.x = TRUE)

# Drop missing CC and convert to numeric
# Not all ICDs resolve to a CC by definition
x <- x[!is.na(x$cc), ]
x$cc <- as.numeric(x$cc)

# keep id, date, and cc columns only, reorder
x <- x[, c(visit_name, date_name, "year", "cc")]

# Keep only unique records
# Multiple ICDs for a patient can resolve to same CC
x <- unique(x)

# Import hierarchy mappings, and duplicate the ifcc column
# needed for future matching
hierarchy <- icd::icd_map_cc_hcc
hierarchy$cc <- hierarchy$ifcc

# Merge hierarchy rules with patient data
x <- merge(x, hierarchy, all.x = TRUE)

# Create a list of dataframes that contain the CCs that will be zeroed out
todrop <- list()
for (i in 1:6) {
todrop[[i]] <- x[!is.na(x$ifcc), c(3, 4, 5 + i)]
}

# Rename all dataframes in list to same column names
# rbind into a single dataframe
todrop <- lapply(1:length(todrop), function(x) {
names(todrop[[x]]) <- c(visit_name, date_name, "cc")
return(todrop[[x]])
}
)
todrop <- do.call(rbind, todrop)

# Remove all NAs from CC field
todrop <- todrop[!is.na(todrop$cc), ]

# Set flag for all of the CCs to be dropped
todrop$todrop <- TRUE

# Merge drop flags with patient data
x <- merge(x, todrop, all.x = TRUE)

# Drop flagged patients and keep columns of interest
x <- x[is.na(x$todrop), ]
x <- x[, c(visit_name, date_name, "cc")]
names(x) <- c(visit_name, date_name, "hcc")
x
}

#' @rdname icd_comorbid
#' @export
icd10_comorbid_hcc <- function(x,
date_name = "date",
visit_name = NULL,
icd_name = NULL) {
assert_data_frame(x, min.cols = 3, col.names = "unique")
assert(checkString(visit_name), checkNull(visit_name))
assert(checkString(icd_name), checkNull(icd_name))
visit_name <- get_visit_name(x, visit_name)
icd_name <- get_icd_name(x, icd_name)
assert_string(date_name)
assert_string(visit_name)
assert_string(icd_name)

# Add column for year
x$year <- as.numeric(format(x[[date_name]], "%Y"))

# merge CCs to patient data based on ICD and year drop ICD info
x <- merge(x, icd::icd10_map_cc, all.x = TRUE)

# Drop missing CC and convert to numeric
# Not all ICDs resolve to a CC by definition
x <- x[!is.na(x$cc), ]
x$cc <- as.numeric(x$cc)

# keep id, date, and cc columns only, reorder
x <- x[, c(visit_name, date_name, "year", "cc")]

# Keep only unique records
# Multiple ICDs for a patient can resolve to same CC
x <- unique(x)

# Import hierarchy mappings, and duplicate the ifcc column
# needed for future matching
hierarchy <- icd::icd_map_cc_hcc
hierarchy$cc <- icd::icd_map_cc_hcc$ifcc

# Merge hierarchy rules with patient data
x <- merge(x, hierarchy, all.x = TRUE)

# Create a list of dataframes that contain the CCs that will be zeroed out
todrop <- list()
for (i in 1:6) {
todrop[[i]] <- x[!is.na(x$ifcc), c(3, 4, 5 + i)]
}

# Rename all dataframes in list to same column names
# rbind into a single dataframe
todrop <- lapply(1:length(todrop), function(x) {
names(todrop[[x]]) <- c(visit_name, date_name, "cc")
return(todrop[[x]])
}
)
todrop <- do.call(rbind, todrop)

# Remove all NAs from CC field
todrop <- todrop[!is.na(todrop$cc), ]

# Set flag for all of the CCs to be dropped
todrop$todrop <- TRUE

# Merge drop flags with patient data
x <- merge(x, todrop, all.x = TRUE)

# Drop flagged patients and keep columns of interest
x <- x[is.na(x$todrop), ]
x <- x[, c(visit_name, date_name, "cc")]
names(x) <- c(visit_name, date_name, "hcc")
x
}

#' @rdname icd_comorbid
#' @export
icd_comorbid_ahrq <- function(x, icd_name = get_icd_name(x), ...) {
Expand Down Expand Up @@ -636,6 +789,29 @@ icd_comorbid_quan_deyo <- function(x, icd_name = get_icd_name(x), ...) {
stop("could not guess the ICD version using icd_name = ", icd_name)
}

#' @details Applying CMS Hierarchical Condition Categories
#' \code{icd_comorbid_hcc} functions differently from the rest of the
#' comorbidity assignment functions. This is because CMS publishes a specific
#' ICD to Condition Category mapping including all child ICDs. In addition,
#' while these mappings were the same for 2007-2012, after 2013 there are
#' annual versions. In addition, there is a many:many linkage between ICD and
#' Condition Categories (CC). Once CCs are assigned, a series of hierarchy
#' rules (which can also change annually) are applied to create HCCs.
#' @rdname icd_comorbid
#' @param date column representing, the date each record took place, as in each
#' year there is a different ICD9/10 to CC mapping). This is only necessary
#' for HCC mappings.
#' @export
icd_comorbid_hcc <- function(x, icd_name = get_icd_name(x), ...) {
ver <- icd_guess_version.data.frame(x, icd_name = icd_name)
if (ver == "icd9")
icd9_comorbid_hcc(x, icd_name = icd_name, ...)
else if (ver == "icd10")
icd10_comorbid_hcc(x, icd_name = icd_name, ...)
else
stop("could not guess the ICD version using icd_name = ", icd_name)
}

#' Apply hierarchy and choose naming for each comorbidity map
#'
#' Re-used by ICD-9 and ICD-10 versions which have the same rules.
Expand Down
31 changes: 28 additions & 3 deletions R/datadocs.R
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ NULL
#' @keywords datasets
#' @format list of character vectors, each named by co-morbidity
#' @references Sharabiani, Mansour T. A., Paul Aylin, and Alex Bottle.
#' "Systematic Review of Comorbidity Indices for Administrative Data." Medical
#' Care December 2012 50, no. 12 (2012): 1109-18.
#' "Systematic Review of Comorbidity Indices for Administrative Data."
#' Medical Care December 2012 50, no. 12 (2012): 1109-18.
#' doi:10.1097/MLR.0b013e31825f64d0.
#' \url{http://www.ncbi.nlm.nih.gov/pubmed/22929993}
#'
Expand All @@ -207,6 +207,31 @@ NULL
#' @aliases elixComorbid icd10_map_elix
NULL

#' Medicare Hierarchical Condition Categories
#'
#' Medicare HCC model was developed to use current year diagnoses and demographics
#' predict current year healthcare expenditure. This classification has been used
#' for additional risk adjustment models. ICD codes are first assigned to numeric
#' Condition Categories (CCs). A hierarchy rule is then applied so that each patient
#' is coded for only the most severe of the Condition Categories in a group. For example,
#' if a patient has metastatic lung cancer, they will only be assigned the CC
#' for "Metastatic Cancer and Acute Leukemia", and will not be assigned the
#' CC for "Lung and other Severe Cancers". Once the hierarchy rules are applied, the codes
#' are referred to as HCCs. This mapping can change over time. It remained the same from
#' 2007-10
#' @docType data
#' @keywords datasets
#' @format \code{dataframe} with 3 columns (\code{icd_code}, \code{cc}, and \code{year})
#' @references Pope, Gregory C., et al.
#' "Diagnostic cost group hierarchical condition category models for Medicare risk adjustment."
#' Health Economics Research, Inc. Waltham, MA (2000).
#' \url{https://www.cms.gov/Research-Statistics-Data-and-Systems/Statistics-Trends-and-Reports/Reports/Downloads/Pope_2000_2.pdf}
#'
#' Risk Adjustment, Centers for Medicare and Medicaid Services
#' \url{https://www.cms.gov/Medicare/Health-Plans/MedicareAdvtgSpecRateStats/Risk-Adjustors.html}
#' @name icd9_map_hcc
#' @aliases icd10_map_hcc icd_nap_cc_hcc

#' Comorbidity names
#'
#' These lists provide correctly sorted names of the comorbidities and their
Expand All @@ -231,7 +256,7 @@ NULL
#' icd_names_quan_elix icd_names_quan_elix_abbrev icd_names_quan_elix_htn
#' icd_names_quan_elix_htn_abbrev icd_names_ahrq icd_names_ahrq_abbrev
#' icd_names_ahrq_htn icd_names_ahrq_htn_abbrev icd_names_charlson
#' icd_names_charlson_abbrev elixComorbidNames elixComorbidNamesAbbrev
#' icd_names_charlson_abbrev icd_names_cc elixComorbidNames elixComorbidNamesAbbrev
#' elixComorbidNamesHtn elixComorbidNamesHtnAbbrev quanElixComorbidNames
#' quanElixComorbidNamesAbbrev quanElixComorbidNamesHtn
#' quanElixComorbidNamesHtnAbbrev ahrqComorbidNames ahrqComorbidNamesAbbrev
Expand Down
Loading