Skip to content

Commit

Permalink
Having a go at #32
Browse files Browse the repository at this point in the history
  • Loading branch information
ellessenne committed Dec 15, 2020
1 parent 60e0567 commit 3a14dfe
Show file tree
Hide file tree
Showing 37 changed files with 1,674 additions and 1,548 deletions.
16 changes: 16 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# comorbidity (development version)

### BREAKING CHANGES

`comorbidity` 0.6.0 modifies the behaviour of the `assign0` argument.

With `comorbidity` 0.5.3 (and below), `assign0` accepted a logical value to either apply a hierachy of comorbidities (`assign0 = TRUE`) or not (`assign0 = FALSE`); the hierarchy was applied to the score (and weighted score) only.

Now, the hierarchy can applied to the single comorbidity domains as well.
With this new version of the `comorbidity` package, you can either apply the hierachy to both domains and scores (`assign0 = "both"`), to scores only (`assign0 = "score"`) or to not apply the hierarchy at all (`assign0 = "none"`).
The latter two correspond to `assign0 = TRUE` and `assign0 = FALSE` from the previous version, respectively:

* `assign0 = "score"` (`comorbidity` 0.6.0) corresponds to `assign0 = "TRUE"` (`comorbidity` 0.5.3);

* `assign0 = "none"` (`comorbidity` 0.6.0) corresponds to `assign0 = "FALSE"` (`comorbidity` 0.5.3).

See #32 on GitHub for more details [@rplzzz].

# comorbidity 0.5.3

* `comorbidity` now accepts `data.table` objects as input (#23);
Expand Down
63 changes: 53 additions & 10 deletions R/comorbidity.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,24 @@
#' @param id Column of `x` containing the individual ID.
#' @param code Column of `x` containing diagnostic codes. Codes must be in upper case with no punctuation in order to be properly recognised.
#' @param score The comorbidity score to compute. Possible choices are the weighted Charlson score (`charlson`) and the weighted Elixhauser score (`elixhauser`). Values are case-insensitive.
#' @param assign0 Apply a hierarchy of comorbidities. If `TRUE`, should a comorbidity be present in a patient with different degrees of severity, then the milder form will be assigned to 0 and therefore not counted. By doing this, a type of comorbidity is not counted more than once in each patient. In particular, the comorbidities that are affected by this argument are:
#' @param assign0 Apply a hierarchy of comorbidities: should a comorbidity be present in a patient with different degrees of severity, then the milder form will be assigned a value of 0.
#' By doing this, a type of comorbidity is not counted more than once in each patient.
#'
#' If `assign0 = "score"` then the hierarchy will be applied to the score and weighted score only, i.e. the comorbidity domains will not be affected.
#' If `assign0 = "both"` then both domains and scores will be affected.
#' Finally, if `assign0 = "none"` no hierarchy is applied.
#' The previous behaviour (`comorbidity <= 0.5.3`) corresponds to:
#' * `assign0 = "score"` replaces `assign0 = TRUE`,
#' * `assign0 = "none"` replaces `assign0 = FALSE`.
#'
#' The comorbidities that are affected by this argument are:
#' * "Mild liver disease" (`mld`) and "Moderate/severe liver disease" (`msld`) for the Charlson score;
#' * "Diabetes" (`diab`) and "Diabetes with complications" (`diabwc`) for the Charlson score;
#' * "Cancer" (`canc`) and "Metastatic solid tumour" (`metacanc`) for the Charlson score;
#' * "Hypertension, uncomplicated" (`hypunc`) and "Hypertension, complicated" (`hypc`) for the Elixhauser score;
#' * "Diabetes, uncomplicated" (`diabunc`) and "Diabetes, complicated" (`diabc`) for the Elixhauser score;
#' * "Solid tumour" (`solidtum`) and "Metastatic cancer" (`metacanc`) for the Elixhauser score.
#'
#' @param icd The version of ICD coding to use. Possible choices are ICD-9-CM (`icd9`) or ICD-10 (`icd10`). Defaults to `icd10`, and values are case-insensitive.
#' @param factorise Return comorbidities as factors rather than numeric, where (1 = presence of comorbidity, 0 = otherwise). Defaults to `FALSE`.
#' @param labelled Attach labels to each comorbidity, compatible with the RStudio viewer via the [utils::View()] function. Defaults to `TRUE`.
Expand Down Expand Up @@ -106,13 +117,24 @@
#' )
#'
#' # Charlson score based on ICD-10 diagnostic codes:
#' comorbidity(x = x, id = "id", code = "code", score = "charlson", assign0 = FALSE)
#' comorbidity(x = x, id = "id", code = "code", score = "charlson", assign0 = "none")
#'
#' # Elixhauser score based on ICD-10 diagnostic codes:
#' comorbidity(x = x, id = "id", code = "code", score = "elixhauser", assign0 = FALSE)
#' comorbidity(x = x, id = "id", code = "code", score = "elixhauser", assign0 = "none")
#' @export

comorbidity <- function(x, id, code, score, assign0, icd = "icd10", factorise = FALSE, labelled = TRUE, tidy.codes = TRUE) {

# x = x
# id = "id"
# code = "code"
# score = "elixhauser"
# assign0 = "both"
# icd = "icd10"
# factorise = FALSE
# labelled = TRUE
# tidy.codes = TRUE

### Check arguments
arg_checks <- checkmate::makeAssertCollection()
# x must be a data.frame (or a data.table)
Expand All @@ -122,14 +144,16 @@ comorbidity <- function(x, id, code, score, assign0, icd = "icd10", factorise =
checkmate::assert_string(code, add = arg_checks)
checkmate::assert_string(score, add = arg_checks)
checkmate::assert_string(icd, add = arg_checks)
# assign0 must be a string with possible values: 'score', 'both', 'none'
checkmate::assert_string(assign0, add = arg_checks)
checkmate::assert_true(assign0 %in% c("score", "both", "none"), add = arg_checks)
# score must be charlson, elixhauser; case insensitive
score <- tolower(score)
checkmate::assert_choice(score, choices = c("charlson", "elixhauser"), add = arg_checks)
# icd must be icd9, icd10; case insensitive
icd <- tolower(icd)
checkmate::assert_choice(icd, choices = c("icd9", "icd10"), add = arg_checks)
# assign0, factorise, labelled, tidy.codes, parallel must be a single boolean value
checkmate::assert_logical(assign0, len = 1, add = arg_checks)
# factorise, labelled, tidy.codes, parallel must be a single boolean value
checkmate::assert_logical(factorise, len = 1, add = arg_checks)
checkmate::assert_logical(labelled, len = 1, add = arg_checks)
checkmate::assert_logical(tidy.codes, len = 1, add = arg_checks)
Expand Down Expand Up @@ -195,19 +219,38 @@ comorbidity <- function(x, id, code, score, assign0, icd = "icd10", factorise =

### Compute Charlson score and Charlson index
if (score == "charlson") {
x$score <- with(x, ami + chf + pvd + cevd + dementia + copd + rheumd + pud + mld * ifelse(msld == 1 & assign0, 0, 1) + diab * ifelse(diabwc == 1 & assign0, 0, 1) + diabwc + hp + rend + canc * ifelse(metacanc == 1 & assign0, 0, 1) + msld + metacanc + aids)
x$score <- with(x, ami + chf + pvd + cevd + dementia + copd + rheumd + pud + mld * ifelse(msld == 1 & assign0 != "none", 0, 1) + diab * ifelse(diabwc == 1 & assign0 != "none", 0, 1) + diabwc + hp + rend + canc * ifelse(metacanc == 1 & assign0 != "none", 0, 1) + msld + metacanc + aids)
x$index <- with(x, cut(score, breaks = c(0, 1, 2.5, 4.5, Inf), labels = c("0", "1-2", "3-4", ">=5"), right = FALSE))
x$wscore <- with(x, ami + chf + pvd + cevd + dementia + copd + rheumd + pud + mld * ifelse(msld == 1 & assign0, 0, 1) + diab * ifelse(diabwc == 1 & assign0, 0, 1) + diabwc * 2 + hp * 2 + rend * 2 + canc * ifelse(metacanc == 1 & assign0, 0, 2) + msld * 3 + metacanc * 6 + aids * 6)
x$wscore <- with(x, ami + chf + pvd + cevd + dementia + copd + rheumd + pud + mld * ifelse(msld == 1 & assign0 != "none", 0, 1) + diab * ifelse(diabwc == 1 & assign0 != "none", 0, 1) + diabwc * 2 + hp * 2 + rend * 2 + canc * ifelse(metacanc == 1 & assign0 != "none", 0, 2) + msld * 3 + metacanc * 6 + aids * 6)
x$windex <- with(x, cut(wscore, breaks = c(0, 1, 2.5, 4.5, Inf), labels = c("0", "1-2", "3-4", ">=5"), right = FALSE))
} else {
x$score <- with(x, chf + carit + valv + pcd + pvd + hypunc * ifelse(hypc == 1 & assign0, 0, 1) + hypc + para + ond + cpd + diabunc * ifelse(diabc == 1 & assign0, 0, 1) + diabc + hypothy + rf + ld + pud + aids + lymph + metacanc + solidtum * ifelse(metacanc == 1 & assign0, 0, 1) + rheumd + coag + obes + wloss + fed + blane + dane + alcohol + drug + psycho + depre)
x$score <- with(x, chf + carit + valv + pcd + pvd + hypunc * ifelse(hypc == 1 & assign0 != "none", 0, 1) + hypc + para + ond + cpd + diabunc * ifelse(diabc == 1 & assign0 != "none", 0, 1) + diabc + hypothy + rf + ld + pud + aids + lymph + metacanc + solidtum * ifelse(metacanc == 1 & assign0 != "none", 0, 1) + rheumd + coag + obes + wloss + fed + blane + dane + alcohol + drug + psycho + depre)
x$index <- with(x, cut(score, breaks = c(-Inf, 0, 1, 4.5, Inf), labels = c("<0", "0", "1-4", ">=5"), right = FALSE))
x$wscore_ahrq <- with(x, chf * 9 + carit * 0 + valv * 0 + pcd * 6 + pvd * 3 + ifelse(hypunc == 1 | hypc == 1, 1, 0) * (-1) + para * 5 + ond * 5 + cpd * 3 + diabunc * ifelse(diabc == 1 & assign0, 0, 0) + diabc * (-3) + hypothy * 0 + rf * 6 + ld * 4 + pud * 0 + aids * 0 + lymph * 6 + metacanc * 14 + solidtum * ifelse(metacanc == 1 & assign0, 0, 7) + rheumd * 0 + coag * 11 + obes * (-5) + wloss * 9 + fed * 11 + blane * (-3) + dane * (-2) + alcohol * (-1) + drug * (-7) + psycho * (-5) + depre * (-5))
x$wscore_vw <- with(x, chf * 7 + carit * 5 + valv * (-1) + pcd * 4 + pvd * 2 + ifelse(hypunc == 1 | hypc == 1, 1, 0) * 0 + para * 7 + ond * 6 + cpd * 3 + diabunc * ifelse(diabc == 1 & assign0, 0, 0) + diabc * 0 + hypothy * 0 + rf * 5 + ld * 11 + pud * 0 + aids * 0 + lymph * 9 + metacanc * 12 + solidtum * ifelse(metacanc == 1 & assign0, 0, 4) + rheumd * 0 + coag * 3 + obes * (-4) + wloss * 6 + fed * 5 + blane * (-2) + dane * (-2) + alcohol * 0 + drug * (-7) + psycho * 0 + depre * (-3))
x$wscore_ahrq <- with(x, chf * 9 + carit * 0 + valv * 0 + pcd * 6 + pvd * 3 + ifelse(hypunc == 1 | hypc == 1, 1, 0) * (-1) + para * 5 + ond * 5 + cpd * 3 + diabunc * ifelse(diabc == 1 & assign0 != "none", 0, 0) + diabc * (-3) + hypothy * 0 + rf * 6 + ld * 4 + pud * 0 + aids * 0 + lymph * 6 + metacanc * 14 + solidtum * ifelse(metacanc == 1 & assign0 != "none", 0, 7) + rheumd * 0 + coag * 11 + obes * (-5) + wloss * 9 + fed * 11 + blane * (-3) + dane * (-2) + alcohol * (-1) + drug * (-7) + psycho * (-5) + depre * (-5))
x$wscore_vw <- with(x, chf * 7 + carit * 5 + valv * (-1) + pcd * 4 + pvd * 2 + ifelse(hypunc == 1 | hypc == 1, 1, 0) * 0 + para * 7 + ond * 6 + cpd * 3 + diabunc * ifelse(diabc == 1 & assign0 != "none", 0, 0) + diabc * 0 + hypothy * 0 + rf * 5 + ld * 11 + pud * 0 + aids * 0 + lymph * 9 + metacanc * 12 + solidtum * ifelse(metacanc == 1 & assign0 != "none", 0, 4) + rheumd * 0 + coag * 3 + obes * (-4) + wloss * 6 + fed * 5 + blane * (-2) + dane * (-2) + alcohol * 0 + drug * (-7) + psycho * 0 + depre * (-3))
x$windex_ahrq <- with(x, cut(wscore_ahrq, breaks = c(-Inf, 0, 1, 4.5, Inf), labels = c("<0", "0", "1-4", ">=5"), right = FALSE))
x$windex_vw <- with(x, cut(wscore_vw, breaks = c(-Inf, 0, 1, 4.5, Inf), labels = c("<0", "0", "1-4", ">=5"), right = FALSE))
}

### If 'assign0 = "both"', then apply hierarchy to individual comorbidity domains too
if (assign0 == "both") {
if (score == "charlson") {
# "Mild liver disease" (`mld`) and "Moderate/severe liver disease" (`msld`)
x$mld[x$msld == 1] <- 0
# "Diabetes" (`diab`) and "Diabetes with complications" (`diabwc`)
x$diab[x$diabwc == 1] <- 0
# "Cancer" (`canc`) and "Metastatic solid tumour" (`metacanc`)
x$canc[x$metacanc == 1] <- 0
} else {
# "Hypertension, uncomplicated" (`hypunc`) and "Hypertension, complicated" (`hypc`)
x$hypunc[x$hypc == 1] <- 0
# "Diabetes, uncomplicated" (`diabunc`) and "Diabetes, complicated" (`diabc`)
x$diabunc[x$diabc == 1] <- 0
# "Solid tumour" (`solidtum`) and "Metastatic cancer" (`metacanc`)
x$solidtum[x$metacanc == 1] <- 0
}
}

### Check output for possible unknown-state errors
.check_output(x = x, id = id, score = score)

Expand Down
37 changes: 15 additions & 22 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ set.seed(1)
# simulate 50 ICD-10 codes for 5 individuals
x <- data.frame(
id = sample(1:5, size = 50, replace = TRUE),
code = sample_diag(n = 50),
stringsAsFactors = FALSE
code = sample_diag(n = 50)
)
x <- x[order(x$id, x$code), ]
print(head(x, n = 15), row.names = FALSE)
Expand All @@ -68,14 +67,12 @@ It is also possible to simulate from two different versions of the ICD-10 coding
set.seed(1)
x1 <- data.frame(
id = sample(1:3, size = 30, replace = TRUE),
code = sample_diag(n = 30),
stringsAsFactors = FALSE
code = sample_diag(n = 30)
)
set.seed(1)
x2 <- data.frame(
id = sample(1:3, size = 30, replace = TRUE),
code = sample_diag(n = 30, version = "ICD10_2011"),
stringsAsFactors = FALSE
code = sample_diag(n = 30, version = "ICD10_2011")
)
# should return TRUE
all.equal(x1, x2)
Expand All @@ -87,14 +84,12 @@ Alternatively, you could use the 2009 version:
set.seed(1)
x1 <- data.frame(
id = sample(1:3, size = 30, replace = TRUE),
code = sample_diag(n = 30, version = "ICD10_2009"),
stringsAsFactors = FALSE
code = sample_diag(n = 30, version = "ICD10_2009")
)
set.seed(1)
x2 <- data.frame(
id = sample(1:3, size = 30, replace = TRUE),
code = sample_diag(n = 30, version = "ICD10_2011"),
stringsAsFactors = FALSE
code = sample_diag(n = 30, version = "ICD10_2011")
)
# should not return TRUE
all.equal(x1, x2)
Expand All @@ -108,8 +103,7 @@ ICD-9 codes can be easily simulated too:
set.seed(2)
x9 <- data.frame(
id = sample(1:3, size = 30, replace = TRUE),
code = sample_diag(n = 30, version = "ICD9_2015"),
stringsAsFactors = FALSE
code = sample_diag(n = 30, version = "ICD9_2015")
)
x9 <- x9[order(x9$id, x9$code), ]
print(head(x9, n = 15), row.names = FALSE)
Expand All @@ -125,29 +119,29 @@ Say we have 3 individuals with a total of 30 ICD-10 diagnostic codes:
set.seed(1)
x <- data.frame(
id = sample(1:3, size = 30, replace = TRUE),
code = sample_diag(n = 30),
stringsAsFactors = FALSE
code = sample_diag(n = 30)
)
```

We could compute the Charlson score, index, and each comorbidity domain:

```{r charlson}
charlson <- comorbidity(x = x, id = "id", code = "code", score = "charlson", icd = "icd10", assign0 = FALSE)
charlson <- comorbidity(x = x, id = "id", code = "code", score = "charlson", icd = "icd10", assign0 = "none")
charlson
```

We set the `assign0` argument to `FALSE` to not apply a hierarchy of comorbidity codes, as described in `?comorbidity::comorbidity`. The default is to assume ICD-10 codes are passed to `comorbidity`:
We set the `assign0` argument to `"none"` to not apply a hierarchy of comorbidity codes, as described in `?comorbidity::comorbidity`.
The default is to assume ICD-10 codes are passed to `comorbidity`:

```{r charlson-2}
charlson.default <- comorbidity(x = x, id = "id", code = "code", score = "charlson", assign0 = FALSE)
charlson.default <- comorbidity(x = x, id = "id", code = "code", score = "charlson", assign0 = "none")
all.equal(charlson, charlson.default)
```

Alternatively, we could compute the Elixhauser score:

```{r elixhauser}
elixhauser <- comorbidity(x = x, id = "id", code = "code", score = "elixhauser", icd = "icd10", assign0 = FALSE)
elixhauser <- comorbidity(x = x, id = "id", code = "code", score = "elixhauser", icd = "icd10", assign0 = "none")
elixhauser
```

Expand All @@ -157,8 +151,7 @@ Conversely, say we have 5 individuals with a total of 100 ICD-9 diagnostic codes
set.seed(3)
x <- data.frame(
id = sample(1:5, size = 100, replace = TRUE),
code = sample_diag(n = 100, version = "ICD9_2015"),
stringsAsFactors = FALSE
code = sample_diag(n = 100, version = "ICD9_2015")
)
```

Expand All @@ -167,14 +160,14 @@ The Charlson and Elixhauser comorbidity codes can be easily computed:
We could compute the Charlson score, index, and each comorbidity domain:

```{r charlson-9}
charlson9 <- comorbidity(x = x, id = "id", code = "code", score = "charlson", icd = "icd9", assign0 = FALSE)
charlson9 <- comorbidity(x = x, id = "id", code = "code", score = "charlson", icd = "icd9", assign0 = "none")
charlson9
```

Alternatively, we could compute the Elixhauser score:

```{r elixhauser-9}
elixhauser9 <- comorbidity(x = x, id = "id", code = "code", score = "elixhauser", icd = "icd9", assign0 = FALSE)
elixhauser9 <- comorbidity(x = x, id = "id", code = "code", score = "elixhauser", icd = "icd9", assign0 = "none")
elixhauser9
```

Expand Down
Loading

0 comments on commit 3a14dfe

Please sign in to comment.