mirror of
https://github.com/agdamsbo/stRoke.git
synced 2024-11-21 20:40:22 +01:00
197 lines
5.4 KiB
R
197 lines
5.4 KiB
R
#' PASE score calculator
|
|
#'
|
|
#' Calculates PASE score from raw questionnaire data.
|
|
#' @param ds data set
|
|
#' @param adjust_work flag to set whether to include 10b type 1.
|
|
#' @param consider.missing character vector of values considered missing.
|
|
#' Default is TRUE.
|
|
#'
|
|
#' @return data.frame
|
|
#' @export
|
|
#' @details
|
|
#' Labelling should be as defined by the questionnaire.
|
|
#' 02-06 should start with 0:3, 02a-06b should start with 1:4.
|
|
#'
|
|
#' ## Regarding work scoring
|
|
#' The score calculation manual available for the PASE questionnaire, all types
|
|
#' of work should be included. According to the article by
|
|
#' Washburn RA. et al (1999) sitting work is not included in the item 10 score.
|
|
#' This differentiation is added with the option to set `adjust_work` to
|
|
#' exclude item 10b category 1 work (set `TRUE`).
|
|
#'
|
|
#' ## Regarding output
|
|
#' Output includes sub scores as well as sums, but also to columns assessing data
|
|
#' quality and completeness. If any field has not been filled, `score_incompletes`
|
|
#' will return `TRUE`. If all measures are missing `score_missings` is `TRUE`.
|
|
#' If `adjust_work==TRUE`, 10b has to be filled, or `score_incompletes` will be
|
|
#' set `TRUE`.
|
|
#'
|
|
#' @examples
|
|
#' summary(pase_calc(stRoke::pase)[,13])
|
|
#' str(pase_calc(stRoke::pase))
|
|
#'
|
|
pase_calc <- function(ds,
|
|
adjust_work = FALSE,
|
|
consider.missing = c("Not available")) {
|
|
|
|
if (ncol(ds) != 21) {
|
|
stop("supplied data set has to contain exactly 21 columns.
|
|
Formatting should follow the stRoke::pase data set.")
|
|
}
|
|
|
|
pase <- ds
|
|
|
|
## Classify all as characters
|
|
## Labelling should be as defined by the questionnaire.
|
|
## 02-06 should start with 0:3, 02a-06b should start with 1:4.
|
|
|
|
pase <- do.call(data.frame, lapply(pase, as.character))
|
|
|
|
## Missings and incompletes
|
|
# Cosidered missing if all data is missing
|
|
missings <- apply(apply(ds, 2, is.na), 1, all)
|
|
|
|
# Considered incomplete if any entry in main answers is missing
|
|
mains <- grep("([0-9]{2}|(09[a-d]))$",colnames(pase))
|
|
|
|
if (length(mains)!=13){
|
|
stop("The supplied dataset does not contain expected variable names.
|
|
Please run str(stRoke::pase) and format your data accordingly.")
|
|
}
|
|
|
|
incompletes <-
|
|
apply(sapply(ds[, mains], function(x) {
|
|
x %in% consider.missing | is.na(x)
|
|
}), 1, any)
|
|
|
|
names(pase) <- c(
|
|
"pase01",
|
|
"pase01b",
|
|
"pase02",
|
|
"pase02a",
|
|
"pase03",
|
|
"pase03b",
|
|
"pase04",
|
|
"pase04b",
|
|
"pase05",
|
|
"pase05b",
|
|
"pase06",
|
|
"pase06b",
|
|
"pase07",
|
|
"pase08",
|
|
"pase09a",
|
|
"pase09b",
|
|
"pase09c",
|
|
"pase09d",
|
|
"pase10",
|
|
"pase10a",
|
|
"pase10b"
|
|
)
|
|
|
|
pase_list <- lapply(unique(substr(names(pase), 5, 6)), function(x) {
|
|
pase[grepl(x, substr(names(pase), 5, 6))]
|
|
})
|
|
names(pase_list) <- unique(substr(names(pase), 5, 6))
|
|
|
|
## PASE 2-6
|
|
|
|
pase_weights <- list(
|
|
"1" = c(
|
|
"1" = 0.11,
|
|
"2" = 0.32,
|
|
"3" = 0.64,
|
|
"4" = 1.07
|
|
),
|
|
"2" = c(
|
|
"1" = 0.25,
|
|
"2" = 0.75,
|
|
"3" = 1.5,
|
|
"4" = 2.5
|
|
),
|
|
"3" = c(
|
|
"1" = 0.43,
|
|
"2" = 1.29,
|
|
"3" = 2.57,
|
|
"4" = 4.29
|
|
)
|
|
)
|
|
|
|
## Multiplication factors
|
|
pase_multip_26 <- c(20, 21, 23, 23, 30)
|
|
|
|
pase_score_26 <- lapply(seq_along(pase_list[2:6]), function(x) {
|
|
df <- pase_list[2:6][[x]]
|
|
# score <- c()
|
|
|
|
## =====================
|
|
## Checking labelling
|
|
if (!all(stRoke::str_extract(df[, 1], "^[0-3]") |>
|
|
as.numeric() |>
|
|
range(na.rm = TRUE) == c(0, 3))) {
|
|
stop("Labelling of 02-06 should start with a number ranging 0-3")
|
|
}
|
|
|
|
if (!all(stRoke::str_extract(df[, 2], "^[1-4]") |>
|
|
as.numeric() |>
|
|
range(na.rm = TRUE) == c(1, 4))) {
|
|
stop("Labelling of 02-06 subscores should start with a number ranging 1-4")
|
|
}
|
|
|
|
## =====================
|
|
|
|
## Extracting the first string element in main entry
|
|
n1 <- stRoke::str_extract(df[, 1],"^[0-3]") |> as.numeric()
|
|
## Extracting the first string element in subentry
|
|
n2 <- stRoke::str_extract(df[, 2],"^[1-4]") |> as.numeric()
|
|
|
|
score <- c()
|
|
for (i in seq_along(n1)) {
|
|
|
|
ind1 <- match(n1[i],seq_along(pase_weights))
|
|
|
|
if (is.na(ind1)){
|
|
score[i] <- n1[i]
|
|
} else {
|
|
score[i] <- pase_weights[[ind1]][n2[i]] * pase_multip_26[x]
|
|
}
|
|
|
|
}
|
|
score
|
|
})
|
|
|
|
names(pase_score_26) <- paste0("pase_score_", names(pase_list[2:6]))
|
|
|
|
## PASE 7-9d
|
|
pase_multip_79 <- c(25, 25, 30, 36, 20, 35)
|
|
|
|
pase_score_79 <-
|
|
data.frame(t(t(
|
|
sapply(Reduce(cbind,pase_list[7:9]),function(j){
|
|
grepl("[Jj]a",j)
|
|
}) + 0 # short hand logic to numeric
|
|
) * pase_multip_79))
|
|
|
|
names(pase_score_79) <-
|
|
paste0("pase_score_", sub("pase","",names(pase_score_79)))
|
|
|
|
## PASE 10
|
|
## Completely ignores if 10b is not completed
|
|
pase_score_10 <- 21 * suppressWarnings(as.numeric(pase_list[[10]][[2]])) / 7
|
|
|
|
if (adjust_work){
|
|
# Only includes work time if 10b is != 1
|
|
pase_score_10[substr(pase_list[[10]][[3]],1,1) == "1"] <- 0
|
|
# Consequently consider "Not available" in 10b as incomplete
|
|
incompletes[ds[,21] %in% consider.missing & !incompletes & !is.na(incompletes)] <- TRUE
|
|
}
|
|
|
|
pase_score <- cbind(pase_score_26, pase_score_79, pase_score_10)
|
|
|
|
data.frame(
|
|
pase_score,
|
|
pase_score_sum = rowSums(pase_score, na.rm = TRUE),
|
|
pase_score_missings = missings,
|
|
pase_score_incompletes = incompletes
|
|
)
|
|
}
|