library(shiny)
library(forcats)
library(tidyverse)
library(here)
library(hablar)
library(janitor)
library(gt)Appendix H — QST CRF Data Quality Checks
This document goes over quality checks for the QST Case Report Form (CRF). The headings in the sidebar help the user navigate to their desired content.
H.1 Read in Data and write functions
H.1.1 Load Libraries
H.1.2 Function
Write a function to remove columns where all rows have NA, this is will remove duplicate columns for the the Thoracotomy/TKA cohort
not_all_na <- function(x) any(!is.na(x))H.2 CRF Quality checks
H.2.1 Quantitative Sensory Testing (QST)
Read in QST data, We will call this qst
qst <- read.csv(here("data", "qst", "qst-2024-11-06.csv")) %>%
retype()We will also read in Imaging data since the information on recalibration is recorded in the Imaging CRF. We will later merge field names related to recalibration with the imaging data.
tka_img_4_qst <- read.csv(here("data", "imaging", "imaging-2024-11-06.csv")) %>%
filter(redcap_repeat_instrument == "imaging_mcc1_v09") %>%
select(
record_id,
redcap_event_name,
redcap_data_access_group,
redcap_repeat_instance,
fmricuffcontrarecal,
fmricuffcalfpressurerecal,
fmricuffipyn,
fmricuffcompletescl,
imaging_mcc1_v09_complete
) %>%
filter(imaging_mcc1_v09_complete == 2 & !is.na(redcap_repeat_instance)) %>%
group_by(record_id, redcap_event_name) %>%
top_n(1, redcap_repeat_instance) %>%
ungroup() %>%
select(where(not_all_na))Remove test records
test_records <- c(
"10000",
"15000",
"20000",
"25000",
"40000",
"50000",
"60000",
"70000",
"80000",
"90000",
"100000",
"110000",
"120000"
)
qst <- qst %>%
filter(!record_id %in% test_records)Create a column for cohort type called “cohort”
qst <- qst %>%
mutate(
cohort = case_when(
record_id >= 10000 & record_id < 15000 | record_id >= 25000 ~ "TKA",
TRUE ~ "Thoracic"
)
)H.2.2 Data Dictionary
Read in data dictionary and remove duplicate field names
qst_dict <- read_csv(here(
"data",
"qst",
"qst-Data-Dictionary-2024-11-06.csv"
)) %>%
distinct(field_name, .keep_all = TRUE)H.2.3 New field name(s):
Add the field name “cohort” to the data dictionary
# Create field names
cohort_new_row <- data.frame(
field_name = "cohort",
field_type = "Character",
field_note = "Type of surgical cohort",
select_choices_or_calculations = "TKA,Thoracic"
)
# Add the new row after the last row
qst_dict <- qst_dict %>%
slice(1:nrow(.)) %>%
add_row(.after = nrow(.), !!!cohort_new_row)H.2.4 TKA QST
tka_qst <- qstkeep subjects from the TKA cohort, with the most recent baseline visit and merge with QST data.
tka_qst <- tka_qst %>%
filter(cohort == "TKA") %>%
filter(redcap_repeat_instrument == "qst_mcc1_v03") %>%
filter(qst_mcc1_v03_complete == 2 & !is.na(redcap_repeat_instance)) %>%
group_by(record_id, redcap_event_name) %>%
top_n(1, redcap_repeat_instance) %>%
ungroup() %>%
select(where(not_all_na))
tka_qst <- left_join(
tka_qst,
tka_img_4_qst,
by = intersect(names(tka_qst), names(tka_img_4_qst))
)H.2.5 Pressure Pain Thresholds (PPT)
keep subjects with completed QST and PPT test completed.
qdata2 <- tka_qst %>%
filter(qst_mcc1_v03_complete == 2) %>%
filter(pptcompleteyn == 2 | pptcompleteyn == 1 | pptcompleteyn == 3)H.2.5.0.1 Flag 1:
Check if the location of index site was entered [both sites =1 OR 3 = Index site (med/lat joint line)].
qerror1 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
filter(is.na(pptpainlocation)) %>%
add_column(error_type = "Location of index site not entered") %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.2 Flag 2:
Remote site (contralateral deltoid)
Check for missing or mismatch in PPT ratings for Remote site.
Repetition 1:
qerror2 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
mutate(ppt_contr_diff1 = pptremote1val - pptremote1val1) %>%
filter(ppt_contr_diff1 != 0 | is.na(ppt_contr_diff1)) %>%
add_column(
error_type = "PPT Repetition 1:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.3 Flag 3:
Repetition 2:
qerror3 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
mutate(ppt_contr_diff2 = pptremote2val - pptremote2val1) %>%
filter(ppt_contr_diff2 != 0 | is.na(ppt_contr_diff2)) %>%
add_column(
error_type = "PPT repetition 2:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.4 Flag 4:
Repetition 3:
qerror4 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
mutate(ppt_contr_diff3 = pptremote3val - pptremote3val1) %>%
filter(ppt_contr_diff3 != 0 | is.na(ppt_contr_diff3)) %>%
add_column(
error_type = "PPT repetition 3:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.5 Flag 5:
Index site (med/lat joint line)
Check for missing or mismatch in PPT ratings for the index site.
Repetition 1:
qerror5 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
mutate(ppt_index_diff1 = pptindex1val - pptindex1val1) %>%
filter(ppt_index_diff1 != 0 | is.na(ppt_index_diff1)) %>%
add_column(
error_type = "PPT Repetition 1:Missing or mismatch in PPT ratings for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.6 Flag 6:
Repetition 2:
qerror6 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
mutate(ppt_index_diff2 = pptindex2val - pptindex2val1) %>%
filter(ppt_index_diff2 != 0 | is.na(ppt_index_diff2)) %>%
add_column(
error_type = "PPT Repetition 2:Missing or mismatch in PPT ratings for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.7 Flag 7:
Repetition 3:
qerror7 <- qdata2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
mutate(ppt_index_diff3 = pptindex3val - pptindex3val1) %>%
filter(ppt_index_diff3 != 0 | is.na(ppt_index_diff3)) %>%
add_column(
error_type = "PPT Repetition 3:Missing or mismatch in PPT ratings for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.8 Flag 8:
Check if PPT was performed on remote site (pptcompleteyn == 2) but PPT information was filled out for the index site.
qerror8 <- qdata2 %>%
filter(pptcompleteyn == 2) %>%
mutate(
index1 = case_when(
(!is.na(pptindex1val) & !is.na(pptindex1val1)) |
(!is.na(pptindex2val) & !is.na(pptindex2val1)) |
(!is.na(pptindex3val) & !is.na(pptindex3val1)) ~
1,
TRUE ~ 0
)
) %>%
filter(index1 == 1) %>%
add_column(
error_type = "PPT: Remote site was checked but PPT information was filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.9 Flag 9:
Check if PPT was performed on both sites (pptcompleteyn == 1) but PPT information was not filled out for the index site.
qerror9 <- qdata2 %>%
filter(pptcompleteyn == 1) %>%
mutate(
index2 = case_when(
(is.na(pptindex1val) & is.na(pptindex1val1)) |
(is.na(pptindex2val) & is.na(pptindex2val1)) |
(is.na(pptindex3val) & is.na(pptindex3val1)) ~
1,
TRUE ~ 0
)
) %>%
filter(index2 == 1) %>%
add_column(
error_type = "PPT: Both sites were checked but PPT information was not filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.10 Flag 10:
Check if PPT was performed on the index site (pptcompleteyn == 3) but PPT information was filled out for the remote site
qerror10 <- qdata2 %>%
filter(pptcompleteyn == 3) %>%
mutate(
remote1 = case_when(
(!is.na(pptremote1val) & !is.na(pptremote1val1)) |
(!is.na(pptremote2val) & !is.na(pptremote2val1)) |
(!is.na(pptremote3val) & !is.na(pptremote3val1)) ~
1,
TRUE ~ 0
)
) %>%
filter(remote1 == 1) %>%
add_column(
error_type = "PPT: Index site was checked but PPT information was filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.11 Flag 11:
Check if PPT was performed on the both sites (pptcompleteyn == 1) but PPT information was not filled out for the remote site
qerror11 <- qdata2 %>%
filter(pptcompleteyn == 1) %>%
mutate(
remote2 = case_when(
(is.na(pptremote1val) & is.na(pptremote1val1)) |
(is.na(pptremote2val) & is.na(pptremote2val1)) |
(is.na(pptremote3val) & is.na(pptremote3val1)) ~
1,
TRUE ~ 0
)
) %>%
filter(remote2 == 1) %>%
add_column(
error_type = "PPT: Both sites were checked but PPT information was not filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.12 Flag 12:
Check if information was available to compute mean PPT values at the index site = primary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
qerror12 <- qdata2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 3)) %>%
rowwise() %>%
mutate(mean1 = mean(c(pptindex1val, pptindex2val, pptindex3val))) %>%
filter(is.na(mean1)) %>%
add_column(
error_type = "PPT: Not enough information was available to compute mean PPT values at the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.5.0.13 Flag 13:
Check if information was available to compute mean PPT values at the remote site = secondary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
qerror13 <- qdata2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 2)) %>%
rowwise() %>%
mutate(mean2 = mean(c(pptremote1val, pptremote2val, pptremote3val))) %>%
filter(is.na(mean2)) %>%
add_column(
error_type = "PPT: Not enough information was available to compute mean PPT values at the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6 Temporal Summation (TS):
Keep subjects with completed QST and TS test.
tr.complete <- tka_qst %>%
filter(qst_mcc1_v03_complete == 2) %>%
filter(tscompleted == 2 | tscompleted == 1 | tscompleted == 3)If TS was completed for both sites then information on at least 1 repetition for both sites should be available.
Create a field name for each repetition (initial and final) and assign 1 if at least one repetition has information without mismatch errors or missingness.
tka_ts_recoded <- tr.complete %>%
mutate(ts_contr_init1 = tsrep1initialpainrem - tsrep1initialpainrem_d) %>%
mutate(ts_contr_fin1 = tsrep1finalpainrem - tsrep1finalpainrem_d) %>%
mutate(ts_contr_init2 = tsrep2initialpainrem - tsrep2initialpainrem_d) %>%
mutate(ts_contr_fin2 = tsrep2finalpainrem - tsrep2finalpainrem_d) %>%
mutate(ts_contr_init3 = tsinitialpainremsclr3 - tsinitialpainremscl1r3) %>%
mutate(ts_contr_fin3 = tsfinalpainremsclr3 - tsfinalpainremscl1r3) %>%
mutate(
trrep1 = case_when(
(tscompleted == 1 | tscompleted == 2) &
ts_contr_init1 == 0 &
ts_contr_fin1 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
trrep2 = case_when(
(tscompleted == 1 | tscompleted == 2) &
ts_contr_init2 == 0 &
ts_contr_fin2 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
trrep3 = case_when(
(tscompleted == 1 | tscompleted == 2) &
ts_contr_init3 == 0 &
ts_contr_fin3 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(ts_ind_init1 = tsrep1initialpainindex - tsrep1initialpainindex_d) %>%
mutate(ts_ind_fin1 = tsrep1finalpainindex - tsrep1finalpainindex_d) %>%
mutate(ts_ind_init2 = tsinitialpainindexsclr2 - tsinitialpainindexscl1r2) %>%
mutate(ts_ind_fin2 = tsfinalpainindexsclr2 - tsfinalpainindexscl1r2) %>%
mutate(ts_ind_init3 = tsinitialpainindexsclr3 - tsinitialpainindexscl1r3) %>%
mutate(ts_ind_fin3 = tsfinalpainindexsclr3 - tsfinalpainindexscl1r3) %>%
mutate(
indrep1 = case_when(
(tscompleted == 1 | tscompleted == 3) &
ts_ind_init1 == 0 &
ts_ind_fin1 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
indrep2 = case_when(
(tscompleted == 1 | tscompleted == 3) &
ts_ind_init2 == 0 &
ts_ind_fin2 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
indrep3 = case_when(
(tscompleted == 1 | tscompleted == 3) &
ts_ind_init3 == 0 &
ts_ind_fin3 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
one_rem = case_when(trrep1 == 1 | trrep2 == 1 | trrep3 ~ 1, TRUE ~ 0)
) %>%
mutate(
one_ind = case_when(indrep1 == 1 | indrep2 == 1 | indrep3 ~ 1, TRUE ~ 0)
) %>%
mutate(one_rep = case_when(one_rem == 1 & one_ind == 1 ~ 1, TRUE ~ 0))H.2.6.0.1 Flag 14:
Check if TS was completed for both sites and at least 1 repetition for both sites had no mismatch errors or missing data.
qerror14 <- tka_ts_recoded %>%
filter(tscompleted == 1 & one_rep == 0) %>%
add_column(
error_type = "TS:TS was completed for both sites and at least 1 repetition for both sites had no mismatch errors or missing data"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.2 Flag 15:
Check if TS was completed for the remote site and at least 1 repetition had no mismatch errors or missing data.
qerror15 <- tka_ts_recoded %>%
filter(tscompleted == 2 & one_rem == 0) %>%
add_column(
error_type = "TS:TS was completed for the remote site and at least 1 repetition had no mismatch errors or missing data"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.3 Flag 16:
Check if TS was completed for the index site and at least 1 repetition had no mismatch errors or missing data.
qerror16 <- tka_ts_recoded %>%
filter(tscompleted == 3 & one_ind == 0) %>%
add_column(
error_type = "TS:TS was completed for the index site and at least 1 repetition had no mismatch errors or missing data"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.4 Flag 17
Check for missing after sensation at 15 secs if TS Remote site (contralateral deltoid) was completed
qerror17 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
filter(is.na(tsfinalpainremafts15)) %>%
add_column(
error_type = "TS: Missing after sensation at 15 secs if TS Remote site (contralateral deltoid) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.5 Flag 18
Check for missing after sensation at 30 secs if TS Remote site (contralateral deltoid) was completed
qerror18 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
filter(is.na(tsfinalpainremafts30)) %>%
add_column(
error_type = "TS: Missing after sensation at 30 secs if TS Remote site (contralateral deltoid) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.6 Flag 19
Check for missing after sensation at 15 secs if TS Index site (med/lat knee) was completed
qerror19 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
filter(is.na(tsfinalpainindafts15)) %>%
add_column(
error_type = "TS: Missing after sensation at 15 secs if TS Index site (med/lat knee) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.7 Flag 20
Check for missing after sensation at 30 secs if TS Index site (med/lat knee) was completed
qerror20 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
filter(is.na(tsfinalpainindafts30)) %>%
add_column(
error_type = "TS: Missing after sensation at 30 secs if TS Index site (med/lat knee) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.8 Flag 21:
Check if TS was performed on the remote site but pain ratings were filled out for the index site.
qerror19 <- tr.complete %>%
filter(tscompleted == 2 & tscompleted != 3) %>%
mutate(
ts.index1 = case_when(
(!is.na(tsrep1initialpainindex) & !is.na(tsrep1initialpainindex_d)) |
(!is.na(tsrep1finalpainindex) & !is.na(tsrep1finalpainindex_d)) |
(!is.na(tsinitialpainindexsclr2) & !is.na(tsinitialpainindexscl1r2)) |
(!is.na(tsfinalpainindexsclr2) & !is.na(tsfinalpainindexscl1r2)) |
(!is.na(tsinitialpainindexsclr3) & !is.na(tsinitialpainindexscl1r3)) |
(!is.na(tsfinalpainindexsclr3) & !is.na(tsfinalpainindexscl1r3)) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.index1 == 1) %>%
add_column(
error_type = "TS:Remote site was checked but pain ratings were filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.9 Flag 22:
Check if TS was performed on both sites but pain ratings were not filled out for the index site.
qerror22 <- tr.complete %>%
filter(tscompleted == 1) %>%
mutate(
ts.bothindex1 = case_when(
is.na(tsrep1initialpainindex) &
is.na(tsrep1initialpainindex_d) &
is.na(tsrep1finalpainindex) &
is.na(tsrep1finalpainindex_d) &
is.na(tsinitialpainindexsclr2) &
is.na(tsinitialpainindexscl1r2) &
is.na(tsfinalpainindexsclr2) &
is.na(tsfinalpainindexscl1r2) &
is.na(tsinitialpainindexsclr3) &
is.na(tsinitialpainindexscl1r3) &
is.na(tsfinalpainindexsclr3) &
is.na(tsfinalpainindexscl1r3) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.bothindex1 == 1) %>%
add_column(
error_type = "TS:Both sites were checked but pain ratings were not filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.10 Flag 23:
Check if TS was performed on both sites but pain ratings were not filled out for the remote.
qerror23 <- tr.complete %>%
filter(tscompleted == 1) %>%
mutate(
ts.bothrem1 = case_when(
is.na(tsrep1initialpainrem) &
is.na(tsrep1initialpainrem_d) &
is.na(tsrep1finalpainrem) &
is.na(tsrep1finalpainrem_d) &
is.na(tsrep2initialpainrem) &
is.na(tsrep2initialpainrem_d) &
is.na(tsrep2finalpainrem) &
is.na(tsrep2finalpainrem_d) &
is.na(tsinitialpainremsclr3) &
is.na(tsinitialpainremscl1r3) &
is.na(tsfinalpainremsclr3) &
is.na(tsfinalpainremscl1r3) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.bothrem1 == 1) %>%
add_column(
error_type = "TS:Both sites were checked but pain ratings were not filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.11 Flag 24:
Check if TS was performed on the index site but pain ratings were filled out for the remote site.
qerror22 <- tr.complete %>%
filter(tscompleted == 3 & tscompleted != 2) %>%
mutate(
ts.remote1 = case_when(
(!is.na(tsrep1initialpainrem) & !is.na(tsrep1initialpainrem_d)) |
(!is.na(tsrep1finalpainrem) & !is.na(tsrep1finalpainrem_d)) |
(!is.na(tsrep2initialpainrem) & !is.na(tsrep2initialpainrem_d)) |
(!is.na(tsrep2finalpainrem) & !is.na(tsrep2finalpainrem_d)) |
(!is.na(tsinitialpainremsclr3) & !is.na(tsinitialpainremscl1r3)) |
(!is.na(tsfinalpainremsclr3) & !is.na(tsfinalpainremscl1r3)) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.remote1 == 1) %>%
add_column(
error_type = "TS:index site was checked but pain ratings were filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.12 Flag 25
Check if information was available to compute primary outcome: Mean of 3 MTS Difference scores computed (Max – initial), (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions, if a record has < 3 repetitions, it will be flagged.
Primary outcome for the Index site.
qerror25 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(
max.rep1.index = pmax(tsrep1finalpainindex, tsrep1initialpainindex)
) %>%
mutate(diff.rep1.index = max.rep1.index - tsrep1initialpainindex) %>%
mutate(
max.rep2.index = pmax(tsfinalpainindexsclr2, tsinitialpainindexsclr2)
) %>%
mutate(diff.rep2.index = max.rep2.index - tsinitialpainindexsclr2) %>%
mutate(
max.rep3.index = pmax(tsfinalpainindexsclr3, tsinitialpainindexsclr3)
) %>%
mutate(diff.rep3.index = max.rep3.index - tsinitialpainindexsclr3) %>%
mutate(diff.rep1.index = as.numeric(diff.rep1.index)) %>%
mutate(diff.rep2.index = as.numeric(diff.rep2.index)) %>%
mutate(diff.rep3.index = as.numeric(diff.rep3.index)) %>%
rowwise() %>%
mutate(
mean.index = mean(c(diff.rep1.index, diff.rep2.index, diff.rep3.index))
) %>%
filter(is.na(mean.index)) %>%
add_column(
error_type = "TS: Not enough information was available to compute primary outcome for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.13 Flag 26
Primary outcome for the Remote site.
qerror26 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(max.rep1.remote = pmax(tsrep1initialpainrem, tsrep1finalpainrem)) %>%
mutate(diff.rep1.remote = max.rep1.remote - tsrep1initialpainrem) %>%
mutate(max.rep2.remote = pmax(tsrep2initialpainrem, tsrep2finalpainrem)) %>%
mutate(diff.rep2.remote = max.rep2.remote - tsrep2initialpainrem) %>%
mutate(max.rep3.remote = pmax(tsinitialpainremsclr3, tsfinalpainremsclr3)) %>%
mutate(diff.rep3.remote = max.rep3.remote - tsinitialpainremsclr3) %>%
mutate(diff.rep1.remote = as.numeric(diff.rep1.remote)) %>%
mutate(diff.rep2.remote = as.numeric(diff.rep2.remote)) %>%
mutate(diff.rep3.remote = as.numeric(diff.rep3.remote)) %>%
rowwise() %>%
mutate(
mean.remote = mean(c(diff.rep1.remote, diff.rep2.remote, diff.rep3.remote))
) %>%
filter(is.na(mean.remote)) %>%
add_column(
error_type = "TS: Not enough information was available to compute primary outcome for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.14 Flag 27
Check if information was available to compute secondary outcome: “Mean of 3 Wind-up ratios (WUR) computed ([Max +1]/ [initial +1]). (1 added to handle possibility of zero initial pain rating in denominator).” (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions, if a record has < 3 repetitions, it will be flagged
Secondary outcome for the index site
qerror27 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(
max.rep1.index1 = 1 + (pmax(tsrep1finalpainindex, tsrep1initialpainindex))
) %>%
mutate(init.rep1.index1 = 1 + (tsrep1initialpainindex)) %>%
mutate(div.rep1.index1 = max.rep1.index1 / init.rep1.index1) %>%
mutate(
max.rep2.index1 = 1 + (pmax(tsfinalpainindexsclr2, tsinitialpainindexsclr2))
) %>%
mutate(init.rep2.index1 = 1 + (tsinitialpainindexsclr2)) %>%
mutate(div.rep2.index1 = max.rep2.index1 / init.rep2.index1) %>%
mutate(
max.rep3.index1 = 1 + (pmax(tsfinalpainindexsclr3, tsinitialpainindexsclr3))
) %>%
mutate(init.rep3.index1 = 1 + (tsinitialpainindexsclr3)) %>%
mutate(div.rep3.index1 = max.rep3.index1 / init.rep3.index1) %>%
rowwise() %>%
mutate(
mean.sec.index = mean(c(div.rep1.index1, div.rep2.index1, div.rep3.index1))
) %>%
filter(is.na(mean.sec.index)) %>%
add_column(
error_type = "TS: Not enough information was available to compute secondary outcome for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.6.0.15 Flag 28
Secondary outcome for the Remote site.
qerror28 <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(
max.rep1.remote1 = 1 + (pmax(tsrep1initialpainrem, tsrep1finalpainrem))
) %>%
mutate(init.rep1.remote1 = 1 + (tsrep1initialpainrem)) %>%
mutate(div.rep1.remote1 = max.rep1.remote1 / init.rep1.remote1) %>%
mutate(
max.rep2.remote1 = 1 + (pmax(tsrep2initialpainrem, tsrep2finalpainrem))
) %>%
mutate(init.rep2.remote1 = 1 + (tsrep2initialpainrem)) %>%
mutate(div.rep2.remote1 = max.rep2.remote1 / init.rep2.remote1) %>%
mutate(
max.rep3.remote1 = 1 + (pmax(tsinitialpainremsclr3, tsfinalpainremsclr3))
) %>%
mutate(init.rep3.remote1 = 1 + (tsinitialpainremsclr3)) %>%
mutate(div.rep3.remote1 = max.rep3.remote1 / init.rep3.remote1) %>%
rowwise() %>%
mutate(
mean.sec.remote = mean(c(
div.rep1.remote1,
div.rep2.remote1,
div.rep3.remote1
))
) %>%
filter(is.na(mean.sec.remote)) %>%
add_column(
error_type = "TS: Not enough information was available to compute secondary outcome for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7 Conditioned Pain Modulation (CPM):
Keep records with “CPM test completed”
trcpm.complete <- tka_qst %>%
filter(qst_mcc1_v03_complete == 2) %>%
filter(!is.na(cpmcompleteyn) & cpmcompleteyn != 0)H.2.7.0.1 Flag 29:
Check if water temperature was not checked:
qerror29 <- trcpm.complete %>%
filter(cpmcoldwatertempc != 1) %>%
add_column(error_type = "CPM: Water temperature not checked") %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.2 Flag 30:
Check for missing or mismatch in cold water pain ratings at 30 seconds.
qerror30 <- trcpm.complete %>%
filter(
cpmbathrangeyn == 1 | (cpmbathrangeyn == 2 & cpmoutrangetime >= 30)
) %>%
mutate(diff_30 = cpmcoldwaterpain30sscl - cpmcoldwaterpain30sscl1) %>%
filter(diff_30 != 0 | is.na(diff_30)) %>%
add_column(
error_type = "CPM: Missing or mismatch in cold water pain ratings at 30 sec"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.3 Flag 31:
Check for missing or mismatch in cold water pain ratings at 60 seconds.
qerror31 <- trcpm.complete %>%
filter(
cpmbathrangeyn == 1 | (cpmbathrangeyn == 2 & cpmoutrangetime >= 60)
) %>%
mutate(diff_60 = cpmcoldwaterpain60sscl - cpmcoldwaterpain60sscl1) %>%
filter(diff_60 != 0 | is.na(diff_60)) %>%
add_column(
error_type = "CPM: Missing or mismatch in cold water pain ratings at 60 sec"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.4 Flag 32:
Check for missing or mismatch in PPT ratings for Remote site (repetition 1).
qerror32 <- trcpm.complete %>%
mutate(diff_cpm1 = cpmppt1val - cpmppt1val1) %>%
filter(diff_cpm1 != 0 | is.na(diff_cpm1)) %>%
add_column(
error_type = "CPM PPT Rep1:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.5 Flag 33:
Check for missing or mismatch in PPT ratings for Remote site (repetition 2).
qerror33 <- trcpm.complete %>%
mutate(diff_cpm2 = cpmppt2val - cpmppt2val1) %>%
filter(diff_cpm2 != 0 | is.na(diff_cpm2)) %>%
add_column(
error_type = "CPM PPT Rep2:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.6 Flag 34:
Check for missing or mismatch in PPT ratings for Remote site (repetition 3).
qerror34 <- trcpm.complete %>%
mutate(diff_cpm3 = cpmppt3val - cpmppt3val1) %>%
filter(diff_cpm3 != 0 | is.na(diff_cpm3)) %>%
add_column(
error_type = "CPM PPT Rep3:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.7 Flag 35:
Check if information was available to compute primary outcome (A2CPS: Site Manual of Procedures v3.0, pg. 159) i.e. [(pre hand immersion PPT-post immersion PPT)/pre immersion PPT] *100
qerror35 <- trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremote1val, pptremote2val, pptremote3val))) %>%
rowwise() %>%
mutate(mean_post = mean(c(cpmppt1val, cpmppt2val, cpmppt3val))) %>%
mutate(cpm_change = ((mean_pre - mean_post) / mean_pre) * 100) %>%
filter(is.na(cpm_change)) %>%
add_column(
error_type = "CPM: Not enough information to compute primary outcome"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.8 Flag 36:
Check if information was available to compute secondary outcome (A2CPS: Site Manual of Procedures v3.0, pg. 159) i.e. CPM difference score computed as pre hand immersion PPT-post immersion PPT
qerror36 <- trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremote1val, pptremote2val, pptremote3val))) %>%
rowwise() %>%
mutate(mean_post = mean(c(cpmppt1val, cpmppt2val, cpmppt3val))) %>%
mutate(cpm_diff = mean_pre - mean_post) %>%
filter(is.na(cpm_diff)) %>%
add_column(
error_type = "CPM: Not enough information to compute secondary outcome"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.9 Flag 37:
Check If personalized pressure was performed during imaging and there were missing values for cuff Pressure to achieve 4/10 pain outside of scanner during QST as well as missing values for recalibration pressure during imaging.
qerror37 <- tka_qst %>%
mutate(
no.qst = case_when(
is.na(fmricuffcalfpressurerecal) & is.na(fmricuffcalfpressure) ~ 1,
TRUE ~ 0
)
) %>%
mutate(
personal.cuff = case_when(
fmricuffcompletescl == 1 | fmricuffipyn == 1 ~ 1,
TRUE ~ 0
)
) %>%
filter(personal.cuff == 1 & no.qst == 1) %>%
add_column(
error_type = "QST: Missing values for cuff Pressure to achieve 4/10 pain outside of scanner during QST as well as missing values for recalibration pressure during imaging"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.7.0.10 QST Biomarkers
H.2.7.0.10.1 PPT Biomarkers:
Mean PPT values at the index site = primary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
primary_ppt_tka <- qdata2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 3)) %>%
rowwise() %>%
mutate(mean1 = mean(c(pptindex1val, pptindex2val, pptindex3val))) %>%
rename(primary_ppt_tka = mean1) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_ppt_tka
)Mean PPT values at the remote site = secondary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
secondary_ppt_tka <- qdata2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 2)) %>%
rowwise() %>%
mutate(mean2 = mean(c(pptremote1val, pptremote2val, pptremote3val))) %>%
rename(secondary_ppt_tka = mean2) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_ppt_tka
)H.2.7.0.10.2 TS Biomarkers:
Primary outcome: Mean of 3 MTS Difference scores computed (Max – initial), (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions.
Primary outcome for the Index site.
primary_ts_index_tka <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(
max.rep1.index = pmax(tsrep1finalpainindex, tsrep1initialpainindex)
) %>%
mutate(diff.rep1.index = max.rep1.index - tsrep1initialpainindex) %>%
mutate(
max.rep2.index = pmax(tsfinalpainindexsclr2, tsinitialpainindexsclr2)
) %>%
mutate(diff.rep2.index = max.rep2.index - tsinitialpainindexsclr2) %>%
mutate(
max.rep3.index = pmax(tsfinalpainindexsclr3, tsinitialpainindexsclr3)
) %>%
mutate(diff.rep3.index = max.rep3.index - tsinitialpainindexsclr3) %>%
mutate(diff.rep1.index = as.numeric(diff.rep1.index)) %>%
mutate(diff.rep2.index = as.numeric(diff.rep2.index)) %>%
mutate(diff.rep3.index = as.numeric(diff.rep3.index)) %>%
rowwise() %>%
mutate(
mean.index = mean(c(diff.rep1.index, diff.rep2.index, diff.rep3.index))
) %>%
rename(primary_ts_index_tka = mean.index) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_ts_index_tka
)Primary outcome for the Remote site.
primary_ts_remote_tka <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(max.rep1.remote = pmax(tsrep1initialpainrem, tsrep1finalpainrem)) %>%
mutate(diff.rep1.remote = max.rep1.remote - tsrep1initialpainrem) %>%
mutate(max.rep2.remote = pmax(tsrep2initialpainrem, tsrep2finalpainrem)) %>%
mutate(diff.rep2.remote = max.rep2.remote - tsrep2initialpainrem) %>%
mutate(max.rep3.remote = pmax(tsinitialpainremsclr3, tsfinalpainremsclr3)) %>%
mutate(diff.rep3.remote = max.rep3.remote - tsinitialpainremsclr3) %>%
mutate(diff.rep1.remote = as.numeric(diff.rep1.remote)) %>%
mutate(diff.rep2.remote = as.numeric(diff.rep2.remote)) %>%
mutate(diff.rep3.remote = as.numeric(diff.rep3.remote)) %>%
rowwise() %>%
mutate(
mean.remote = mean(c(diff.rep1.remote, diff.rep2.remote, diff.rep3.remote))
) %>%
rename(primary_ts_remote_tka = mean.remote) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_ts_remote_tka
)Secondary outcome: Mean of 3 Wind-up ratios (WUR) computed ([Max +1]/ [initial +1]). (1 added to handle possibility of zero initial pain rating in denominator). (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions, if a record has < 3 repetitions, it will be flagged
Secondary outcome for the index site
secondary_ts_index_tka <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(
max.rep1.index1 = 1 + (pmax(tsrep1finalpainindex, tsrep1initialpainindex))
) %>%
mutate(init.rep1.index1 = 1 + (tsrep1initialpainindex)) %>%
mutate(div.rep1.index1 = max.rep1.index1 / init.rep1.index1) %>%
mutate(
max.rep2.index1 = 1 + (pmax(tsfinalpainindexsclr2, tsinitialpainindexsclr2))
) %>%
mutate(init.rep2.index1 = 1 + (tsinitialpainindexsclr2)) %>%
mutate(div.rep2.index1 = max.rep2.index1 / init.rep2.index1) %>%
mutate(
max.rep3.index1 = 1 + (pmax(tsfinalpainindexsclr3, tsinitialpainindexsclr3))
) %>%
mutate(init.rep3.index1 = 1 + (tsinitialpainindexsclr3)) %>%
mutate(div.rep3.index1 = max.rep3.index1 / init.rep3.index1) %>%
rowwise() %>%
mutate(
mean.sec.index = mean(c(div.rep1.index1, div.rep2.index1, div.rep3.index1))
) %>%
rename(secondary_ts_index_tka = mean.sec.index) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_ts_index_tka
)Secondary outcome for the Remote site.
secondary_ts_remote_tka <- tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(
max.rep1.remote1 = 1 + (pmax(tsrep1initialpainrem, tsrep1finalpainrem))
) %>%
mutate(init.rep1.remote1 = 1 + (tsrep1initialpainrem)) %>%
mutate(div.rep1.remote1 = max.rep1.remote1 / init.rep1.remote1) %>%
mutate(
max.rep2.remote1 = 1 + (pmax(tsrep2initialpainrem, tsrep2finalpainrem))
) %>%
mutate(init.rep2.remote1 = 1 + (tsrep2initialpainrem)) %>%
mutate(div.rep2.remote1 = max.rep2.remote1 / init.rep2.remote1) %>%
mutate(
max.rep3.remote1 = 1 + (pmax(tsinitialpainremsclr3, tsfinalpainremsclr3))
) %>%
mutate(init.rep3.remote1 = 1 + (tsinitialpainremsclr3)) %>%
mutate(div.rep3.remote1 = max.rep3.remote1 / init.rep3.remote1) %>%
rowwise() %>%
mutate(
mean.sec.remote = mean(c(
div.rep1.remote1,
div.rep2.remote1,
div.rep3.remote1
))
) %>%
rename(secondary_ts_remote_tka = mean.sec.remote) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_ts_remote_tka
)H.2.7.0.10.3 CPM Biomarkers:
Primary outcome (A2CPS: Site Manual of Procedures v3.0, pg. 159) i.e. [(pre hand immersion PPT-post immersion PPT)/pre immersion PPT] *100
primary_cpm_tka <- trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremote1val, pptremote2val, pptremote3val))) %>%
rowwise() %>%
mutate(mean_post = mean(c(cpmppt1val, cpmppt2val, cpmppt3val))) %>%
mutate(cpm_change = ((mean_pre - mean_post) / mean_pre) * 100) %>%
rename(primary_cpm_tka = cpm_change) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_cpm_tka
)Secondary outcome (A2CPS: Site Manual of Procedures v3.0, pg. 159) i.e. CPM difference score computed as pre hand immersion PPT-post immersion PPT
secondary_cpm_tka <- trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremote1val, pptremote2val, pptremote3val))) %>%
rowwise() %>%
mutate(mean_post = mean(c(cpmppt1val, cpmppt2val, cpmppt3val))) %>%
mutate(cpm_diff = mean_pre - mean_post) %>%
rename(secondary_cpm_tka = cpm_diff) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_cpm_tka
)Merge computed biomarkers to the “tka_qst” dataset:
tka_qst <- left_join(
tka_qst,
primary_ppt_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_ppt_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
primary_ts_index_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
primary_ts_remote_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_ts_index_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_ts_remote_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
primary_cpm_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_cpm_tka,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
)H.2.7.0.11 New field name(s):
Add field names for the computed biomarkers to the QST data dictionary
# Create field names
primary_ppt_tka_new_row <- data.frame(
field_name = "primary_ppt_tka",
field_type = "numeric",
field_note = "PPT primary biomarker:TKA "
)
secondary_ppt_tka_new_row <- data.frame(
field_name = "secondary_ppt_tka",
field_type = "numeric",
field_note = "PPT secondary biomarker:TKA "
)
primary_ts_index_tka_new_row <- data.frame(
field_name = "primary_ts_index_tka",
field_type = "numeric",
field_note = "TS primary biomarker for the index site:TKA "
)
primary_ts_remote_tka_new_row <- data.frame(
field_name = "primary_ts_remote_tka",
field_type = "numeric",
field_note = "TS primary biomarker for the remote site:TKA "
)
secondary_ts_index_tka_new_row <- data.frame(
field_name = "secondary_ts_index_tka",
field_type = "numeric",
field_note = "TS secondary biomarker for the index site:TKA "
)
secondary_ts_remote_tka_new_row <- data.frame(
field_name = " secondary_ts_remote_tka",
field_type = "numeric",
field_note = "TS secondary biomarker for the remote site:TKA "
)
primary_cpm_tka_new_row <- data.frame(
field_name = " primary_cpm_tka",
field_type = "numeric",
field_note = "CPM primary biomarker:TKA "
)
secondary_cpm_tka_new_row <- data.frame(
field_name = " secondary_cpm_tka",
field_type = "numeric",
field_note = "CPM secondary biomarker:TKA "
)
# Add the new row after the last row
qst_dict <- qst_dict %>%
slice(1:nrow(.)) %>%
add_row(.after = nrow(.), !!!primary_ppt_tka_new_row) %>%
add_row(.after = nrow(.), !!!secondary_ppt_tka_new_row) %>%
add_row(.after = nrow(.), !!!primary_ts_index_tka_new_row) %>%
add_row(.after = nrow(.), !!!primary_ts_remote_tka_new_row) %>%
add_row(.after = nrow(.), !!!secondary_ts_index_tka_new_row) %>%
add_row(.after = nrow(.), !!!secondary_ts_remote_tka_new_row) %>%
add_row(.after = nrow(.), !!!primary_cpm_tka_new_row) %>%
add_row(.after = nrow(.), !!!secondary_cpm_tka_new_row)H.2.7.0.12 Create QST error report for the TKA cohort.
# Specify the common prefix
qst_error <- "qerror"
# Find data frames in the global environment with the specified prefix
qst_list <- mget(ls(pattern = paste0("^", qst_error)))
# Combine the data frames using bind_rows
qst_report <- bind_rows(qst_list) %>%
as_tibble() %>%
mutate_all(as.character) %>%
pivot_wider(names_from = "error_type", values_from = "errors") %>%
mutate_all(~ replace_na(., ""))qst_report %>%
gt() %>%
tab_header(
title = md("**TKA Cohort QST form Error Report**")
) %>%
tab_options(
table.font.size = px(12),
column_labels.font.size = px(12)
) %>%
tab_style(
style = list(cell_fill(color = "#F4F4F4")),
locations = cells_body(columns = record_id)
)| TKA Cohort QST form Error Report | |||||||||||||||||||||||||||||||
| record_id | redcap_data_access_group | redcap_repeat_instrument | redcap_repeat_instance | Location of index site not entered | PPT: Both sites were checked but PPT information was not filled out for the remote site | PPT: Not enough information was available to compute mean PPT values at the index site | PPT: Not enough information was available to compute mean PPT values at the remote site | TS:TS was completed for both sites and at least 1 repetition for both sites had no mismatch errors or missing data | TS: Missing after sensation at 15 secs if TS Remote site (contralateral deltoid) was completed | TS: Missing after sensation at 30 secs if TS Remote site (contralateral deltoid) was completed | TS:Remote site was checked but pain ratings were filled out for the index site | PPT Repetition 1:Missing or mismatch in PPT ratings for Remote site | TS: Missing after sensation at 30 secs if TS Index site (med/lat knee) was completed | TS:Both sites were checked but pain ratings were not filled out for the remote site | TS: Not enough information was available to compute primary outcome for the index site | TS: Not enough information was available to compute primary outcome for the remote site | TS: Not enough information was available to compute secondary outcome for the index site | TS: Not enough information was available to compute secondary outcome for the remote site | CPM: Water temperature not checked | PPT repetition 2:Missing or mismatch in PPT ratings for Remote site | CPM: Missing or mismatch in cold water pain ratings at 30 sec | CPM: Missing or mismatch in cold water pain ratings at 60 sec | CPM PPT Rep2:Missing or mismatch in PPT ratings for Remote site | CPM PPT Rep3:Missing or mismatch in PPT ratings for Remote site | CPM: Not enough information to compute primary outcome | CPM: Not enough information to compute secondary outcome | QST: Missing values for cuff Pressure to achieve 4/10 pain outside of scanner during QST as well as missing values for recalibration pressure during imaging | PPT repetition 3:Missing or mismatch in PPT ratings for Remote site | PPT Repetition 2:Missing or mismatch in PPT ratings for the index site | PPT Repetition 3:Missing or mismatch in PPT ratings for the index site | PPT: Both sites were checked but PPT information was not filled out for the index site |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10216 | rush_university_me | qst_mcc1_v03 | 1 | error | error | error | error | ||||||||||||||||||||||||
| 10222 | rush_university_me | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 25050 | university_of_mich | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10040 | uchicago | qst_mcc1_v03 | 1 | error | error | error | error | error | |||||||||||||||||||||||
| 10643 | uchicago | qst_mcc1_v03 | 1 | error | error | error | error | error | |||||||||||||||||||||||
| 10015 | rush_university_me | qst_mcc1_v03 | 1 | error | error | error | error | error | error | ||||||||||||||||||||||
| 10378 | uchicago | qst_mcc1_v03 | 1 | error | error | error | error | ||||||||||||||||||||||||
| 10637 | uchicago | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10679 | rush_university_me | qst_mcc1_v03 | 1 | error | error | error | error | ||||||||||||||||||||||||
| 10758 | uchicago | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10147 | uchicago | qst_mcc1_v03 | 1 | error | error | error | error | error | error | error | error | ||||||||||||||||||||
| 10360 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10372 | uchicago | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 25048 | university_of_mich | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10013 | rush_university_me | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10018 | rush_university_me | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10181 | rush_university_me | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10066 | uchicago | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10283 | rush_university_me | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10315 | uchicago | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10418 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10436 | uchicago | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10539 | uchicago | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10684 | northshore | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 25136 | university_of_mich | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10738 | uchicago | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10778 | rush_university_me | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10905 | rush_university_me | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10425 | uchicago | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10438 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10696 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10055 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 25157 | university_of_mich | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10363 | uchicago | qst_mcc1_v03 | 1 | error | error | ||||||||||||||||||||||||||
| 10613 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10698 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10872 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10899 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 25051 | university_of_mich | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10201 | uchicago | qst_mcc1_v03 | 1 | error | error | error | error | error | |||||||||||||||||||||||
| 10655 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10703 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10006 | rush_university_me | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10249 | rush_university_me | qst_mcc1_v03 | 1 | error | error | error | |||||||||||||||||||||||||
| 10077 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10103 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10258 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10297 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10327 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10335 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10352 | northshore | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10442 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10483 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
| 10487 | uchicago | qst_mcc1_v03 | 1 | error | |||||||||||||||||||||||||||
H.2.7.0.13 Save:
Save “tka_qst” and data dictionary as .csv files in the folder named “reformatted_QST”
write_csv(
tka_qst,
file = here::here("data", "QST", "Reformatted", "reformatted_tka_qst.csv")
)
write_csv(
qst_dict,
file = here::here("data", "QST", "Reformatted", "updated_qst_dict.csv")
)H.2.8 QST: Thoracotomy cohort
thor_qst <- qstWe will also read in Imaging data since the information on recalibration is recorded in the Imaging CRF. We will later merge field names related to recalibration with the imaging data.
thor_img_4_qst <- read_csv(here(
"data",
"imaging",
"imaging-2024-11-06.csv"
)) %>%
filter(redcap_repeat_instrument == "imaging_mcc2_v01") %>%
select(
record_id,
redcap_event_name,
redcap_data_access_group,
redcap_repeat_instance,
fmricuffcontrarecal,
fmricuffcontrarecal,
fmricuffcalfpressurerecal,
fmricuffipyn,
fmricuffcompletescl,
imaging_mcc2_v01_complete
) %>%
filter(imaging_mcc2_v01_complete == 2 & !is.na(redcap_repeat_instance)) %>%
group_by(record_id, redcap_event_name) %>%
top_n(1, redcap_repeat_instance) %>%
ungroup() %>%
select(where(not_all_na))keep subjects from the Thoracotomy cohort, with the most recent baseline visit and merge with QST data.
thor_qst <- thor_qst %>%
filter(cohort == "Thoracic") %>%
filter(redcap_repeat_instrument == "qst_mcc1_v03") %>%
filter(qst_mcc1_v03_complete == 2 & !is.na(redcap_repeat_instance)) %>%
group_by(record_id, redcap_event_name) %>%
top_n(1, redcap_repeat_instance) %>%
ungroup() %>%
select(where(not_all_na))
thor_qst <- left_join(
thor_qst,
thor_img_4_qst,
by = intersect(names(thor_qst), names(thor_img_4_qst))
)H.2.9 Pressure Pain Thresholds (PPT)
keep subjects with completed QST and PPT test.
qdatam2 <- thor_qst %>%
filter(qst_mcc1_v03_complete == 2) %>%
filter(pptcompleteyn == 2 | pptcompleteyn == 1 | pptcompleteyn == 3)H.2.9.0.1 Flag 1:
Remote site: Shoulder (deltoid muscle), contralateral to surgical chest side.
Check for missing or mismatch in PPT ratings for Remote site.
Repetition 1:
m2qerror1 <- qdatam2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
mutate(ppt_contr_diff1 = pptremoter1val - pptremoter1val_d) %>%
filter(ppt_contr_diff1 != 0 | is.na(ppt_contr_diff1)) %>%
add_column(
error_type = "PPT Repetition 1:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.2 Flag 2:
Repetition 2:
m2qerror2 <- qdatam2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
mutate(ppt_contr_diff2 = pptremoter2val - pptremoter2val_d) %>%
filter(ppt_contr_diff2 != 0 | is.na(ppt_contr_diff2)) %>%
add_column(
error_type = "PPT repetition 2:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.3 Flag 3:
Repetition 3:
m2qerror3 <- qdatam2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
mutate(ppt_contr_diff3 = pptremoter3val - pptremoter3val_d) %>%
filter(ppt_contr_diff3 != 0 | is.na(ppt_contr_diff3)) %>%
add_column(
error_type = "PPT repetition 3:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.4 Flag 4:
Index site: Surgical site, lateral thorax on the midaxillary line in the intercostal space between the fifth and sixth rib
Check for missing or mismatch in PPT ratings for the index site.
Repetition 1:
m2qerror4 <- qdatam2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
mutate(ppt_index_diff1 = pptindxr1val - pptindxr1val_d) %>%
filter(ppt_index_diff1 != 0 | is.na(ppt_index_diff1)) %>%
add_column(
error_type = "PPT Repetition 1:Missing or mismatch in PPT ratings for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.5 Flag 5:
Repetition 2:
m2qerror5 <- qdatam2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
mutate(ppt_index_diff2 = pptindxr2val - pptindxr2val_d) %>%
filter(ppt_index_diff2 != 0 | is.na(ppt_index_diff2)) %>%
add_column(
error_type = "PPT Repetition 2:Missing or mismatch in PPT ratings for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.6 Flag 6:
Repetition 3:
m2qerror6 <- qdatam2 %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 3) %>%
mutate(ppt_index_diff3 = pptindxr3val - pptindxr3val_d) %>%
filter(ppt_index_diff3 != 0 | is.na(ppt_index_diff3)) %>%
add_column(
error_type = "PPT Repetition 3:Missing or mismatch in PPT ratings for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.7 Flag 7:
Check if PPT was performed on remote site (pptcompleteyn == 2) but PPT information was filled out for the index site.
m2qerror7 <- qdatam2 %>%
filter(pptcompleteyn == 2) %>%
mutate(
index1 = case_when(
(!is.na(pptindxr1val) & !is.na(pptindxr1val_d)) |
(!is.na(pptindxr2val) & !is.na(pptindxr2val_d)) |
(!is.na(pptindxr3val) & !is.na(pptindxr3val_d)) ~
1,
TRUE ~ 0
)
) %>%
filter(index1 == 1) %>%
add_column(
error_type = "PPT: Remote site was checked but PPT information was filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.8 Flag 8:
Check if PPT was performed on both sites (pptcompleteyn == 1) but PPT information was not filled out for the index site.
m2qerror8 <- qdatam2 %>%
filter(pptcompleteyn == 1) %>%
mutate(
index2 = case_when(
(is.na(pptindxr1val) & is.na(pptindxr1val_d)) |
(is.na(pptindxr2val) & is.na(pptindxr2val_d)) |
(is.na(pptindxr3val) & is.na(pptindxr3val_d)) ~
1,
TRUE ~ 0
)
) %>%
filter(index2 == 1) %>%
add_column(
error_type = "PPT: Both sites were checked but PPT information was not filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.9 Flag 9:
Check if PPT was performed on the index site (pptcompleteyn == 3) but PPT information was filled out for the remote site
m2qerror9 <- qdatam2 %>%
filter(pptcompleteyn == 3) %>%
mutate(
remote1 = case_when(
(!is.na(pptremoter1val) & !is.na(pptremoter1val_d)) |
(!is.na(pptremoter2val) & !is.na(pptremoter2val_d)) |
(!is.na(pptremoter3val) & !is.na(pptremoter3val_d)) ~
1,
TRUE ~ 0
)
) %>%
filter(remote1 == 1) %>%
add_column(
error_type = "PPT: Index site was checked but PPT information was filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.10 Flag 10:
Check if PPT was performed on the both sites (pptcompleteyn == 1) but PPT information was not filled out for the remote site
m2qerror10 <- qdatam2 %>%
filter(pptcompleteyn == 1) %>%
mutate(
remote2 = case_when(
(is.na(pptremoter1val) & is.na(pptremoter1val_d)) |
(is.na(pptremoter2val) & is.na(pptremoter2val_d)) |
(is.na(pptremoter3val) & is.na(pptremoter3val_d)) ~
1,
TRUE ~ 0
)
) %>%
filter(remote2 == 1) %>%
add_column(
error_type = "PPT: Both sites were checked but PPT information was not filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.11 Flag 11:
Check if information was available to compute mean PPT values at the index site = primary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
m2qerror11 <- qdatam2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 3)) %>%
rowwise() %>%
mutate(mean1 = mean(c(pptindxr1val, pptindxr2val, pptindxr3val))) %>%
filter(is.na(mean1)) %>%
add_column(
error_type = "PPT: Not enough information was available to compute mean PPT values at the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.9.0.12 Flag 12:
Check if information was available to compute mean PPT values at the remote site = secondary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
m2qerror12 <- qdatam2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 2)) %>%
rowwise() %>%
mutate(mean2 = mean(c(pptremoter1val, pptremoter2val, pptremoter3val))) %>%
filter(is.na(mean2)) %>%
add_column(
error_type = "PPT: Not enough information was available to compute mean PPT values at the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10 Temporal Summation (TS):
Keep subjects with completed QST and TS test.
m2tr.complete <- thor_qst %>%
filter(qst_mcc1_v03_complete == 2) %>%
filter(tscompleted == 2 | tscompleted == 1 | tscompleted == 3)If TS was completed for both sites then information on at least 1 repetition for both sites should be available.
Create a field name for each repetition (initial and final) and assign 1 if at least one repetition has information without mismatch errors.
thor_ts_recoded <- m2tr.complete %>%
mutate(ts_contr_init1 = tsremoter1initial - tsremoter1initial_d) %>%
mutate(ts_contr_fin1 = tsremoter1final - tsremoter1final_d) %>%
mutate(ts_contr_init2 = tsremoter2initial - tsremoter2initial_d) %>%
mutate(ts_contr_fin2 = tsremoter2final - tsremoter2final_d) %>%
mutate(ts_contr_init3 = tsremoter3initial - tsremoter3initial_d) %>%
mutate(ts_contr_fin3 = tsremoter3final - tsremoter3final_d) %>%
mutate(
trrep1 = case_when(
(tscompleted == 1 | tscompleted == 2) &
ts_contr_init1 == 0 &
ts_contr_fin1 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
trrep2 = case_when(
(tscompleted == 1 | tscompleted == 2) &
ts_contr_init2 == 0 &
ts_contr_fin2 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
trrep3 = case_when(
(tscompleted == 1 | tscompleted == 2) &
ts_contr_init3 == 0 &
ts_contr_fin3 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(ts_ind_init1 = tsindxr1initial - tsindxr1initial_d) %>%
mutate(ts_ind_fin1 = tsindxr1final - tsindxr1final_d) %>%
mutate(ts_ind_init2 = tsindxr2initial - tsindxr2initial_d) %>%
mutate(ts_ind_fin2 = tsindxr2final - tsindxr2final_d) %>%
mutate(ts_ind_init3 = tsindxr3initial - tsindxr3initial_d) %>%
mutate(ts_ind_fin3 = tsindxr3final - tsindxr3final_d) %>%
mutate(
indrep1 = case_when(
(tscompleted == 1 | tscompleted == 3) &
ts_ind_init1 == 0 &
ts_ind_fin1 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
indrep2 = case_when(
(tscompleted == 1 | tscompleted == 3) &
ts_ind_init2 == 0 &
ts_ind_fin2 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
indrep3 = case_when(
(tscompleted == 1 | tscompleted == 3) &
ts_ind_init3 == 0 &
ts_ind_fin3 == 0 ~
1,
TRUE ~ 0
)
) %>%
mutate(
one_rem = case_when(trrep1 == 1 | trrep2 == 1 | trrep3 ~ 1, TRUE ~ 0)
) %>%
mutate(
one_ind = case_when(indrep1 == 1 | indrep2 == 1 | indrep3 ~ 1, TRUE ~ 0)
) %>%
mutate(one_rep = case_when(one_rem == 1 & one_ind == 1 ~ 1, TRUE ~ 0))H.2.10.0.1 Flag 13:
Check if TS was completed for both sites and at least 1 repetition for both sites had no mismatch errors or missing data.
m2qerror13 <- thor_ts_recoded %>%
filter(tscompleted == 1 & one_rep == 0) %>%
add_column(
error_type = "TS: TS was completed for both sites and at least 1 repetition for both sites has no mismatch errors or missing data"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.2 Flag 14:
Check if TS was completed for the remote site and at least 1 repetition had no mismatch errors or missing data.
m2qerror14 <- thor_ts_recoded %>%
filter(tscompleted == 2 & one_rem == 0) %>%
add_column(
error_type = "TS: TS was completed for the remote site and at least 1 repetition had no mismatch errors or missing data"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.3 Flag 15:
Check if TS was completed for the index site and at least 1 repetition had no mismatch errors or missing data.
m2qerror15 <- thor_ts_recoded %>%
filter(tscompleted == 3 & one_ind == 0) %>%
add_column(
error_type = "TS: TS was completed for the index site and at least 1 repetition had no mismatch errors or missing data"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.4 Flag 16
Check for missing after sensation at 15 secs if TS Remote site (contralateral deltoid) was completed
m2qerror16 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
filter(is.na(tsremoteafter15)) %>%
add_column(
error_type = "TS: Missing after sensation at 15 secs if TS Remote site (contralateral deltoid) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.5 Flag 17
Check for missing after sensation at 30 secs if TS Remote site (contralateral deltoid) was completed
m2qerror17 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
filter(is.na(tsfinalpainremafts31)) %>%
add_column(
error_type = "TS: Missing after sensation at 30 secs if TS Remote site (contralateral deltoid) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.6 Flag 18
Check for missing after sensation at 15 secs if TS Index site was completed
m2qerror18 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
filter(is.na(tsindxafter15)) %>%
add_column(
error_type = "TS: Missing after sensation at 15 secs if TS Index site was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.7 Flag 19
Check for missing after sensation at 30 secs if TS Index site was completed
m2qerror19 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
filter(is.na(tsindxafter30)) %>%
add_column(
error_type = "TS: Missing after sensation at 30 secs if TS Index site (med/lat knee) was completed"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.8 Flag 20:
Check if TS was performed on the remote site but pain ratings were filled out for the index site.
m2qerror20 <- m2tr.complete %>%
filter(tscompleted == 2 & tscompleted != 3) %>%
mutate(
ts.index1 = case_when(
(!is.na(tsindxr1initial) & !is.na(tsindxr1initial_d)) |
(!is.na(tsindxr1final) & !is.na(tsindxr1final_d)) |
(!is.na(tsindxr2initial) & !is.na(tsindxr2initial_d)) |
(!is.na(tsindxr2final) & !is.na(tsindxr2final_d)) |
(!is.na(tsindxr3initial) & !is.na(tsindxr3initial_d)) |
(!is.na(tsindxr3final) & !is.na(tsindxr3final_d)) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.index1 == 1) %>%
add_column(
error_type = "TS:Remote site was checked but pain ratings were filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.9 Flag 21:
Check if TS was performed on both sites but pain ratings were not filled out for the index site.
m2qerror21 <- m2tr.complete %>%
filter(tscompleted == 1) %>%
mutate(
ts.bothindex1 = case_when(
is.na(tsindxr1initial) &
is.na(tsindxr1initial_d) &
is.na(tsindxr1final) &
is.na(tsindxr1final_d) &
is.na(tsindxr2initial) &
is.na(tsindxr2initial_d) &
is.na(tsindxr2final) &
is.na(tsindxr2final_d) &
is.na(tsindxr3initial) &
is.na(tsindxr3initial_d) &
is.na(tsindxr3final) &
is.na(tsindxr3final_d) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.bothindex1 == 1) %>%
add_column(
error_type = "TS:Both sites were checked but pain ratings were not filled out for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.10 Flag 22:
Check if TS was performed on both sites but pain ratings were not filled out for the remote.
m2qerror22 <- m2tr.complete %>%
filter(tscompleted == 1) %>%
mutate(
ts.bothrem1 = case_when(
is.na(tsremoter1initial) &
is.na(tsremoter1initial_d) &
is.na(tsremoter1final) &
is.na(tsremoter1final_d) &
is.na(tsremoter2initial) &
is.na(tsremoter2initial_d) &
is.na(tsremoter2final) &
is.na(tsremoter2final_d) &
is.na(tsremoter3initial) &
is.na(tsremoter3initial_d) &
is.na(tsremoter3final) &
is.na(tsremoter3final_d) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.bothrem1 == 1) %>%
add_column(
error_type = "TS:Both sites were checked but pain ratings were not filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.11 Flag 23:
Check if TS was performed on the index site but pain ratings were filled out for the remote site.
m2qerror23 <- m2tr.complete %>%
filter(tscompleted == 3 & tscompleted != 2) %>%
mutate(
ts.remote1 = case_when(
(!is.na(tsremoter1initial) & !is.na(tsremoter1initial_d)) |
(!is.na(tsremoter1final) & !is.na(tsremoter1final_d)) |
(!is.na(tsremoter2initial) & !is.na(tsremoter2initial_d)) |
(!is.na(tsremoter2final) & !is.na(tsremoter2final_d)) |
(!is.na(tsremoter3initial) & !is.na(tsremoter3initial_d)) |
(!is.na(tsremoter3final) & !is.na(tsremoter3final_d)) ~
1,
TRUE ~ 0
)
) %>%
filter(ts.remote1 == 1) %>%
add_column(
error_type = "TS:index site was checked but pain ratings were filled out for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.12 Flag 24
Check if information was available to compute primary outcome: Mean of 3 MTS Difference scores computed (Max – initial), (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions, if a record has < 3 repetitions, it will be flagged.
Primary outcome for the Index site.
m2qerror24 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(max.rep1.index = pmax(tsindxr1final, tsindxr1initial)) %>%
mutate(diff.rep1.index = max.rep1.index - tsindxr1initial) %>%
mutate(max.rep2.index = pmax(tsindxr2final, tsindxr2initial)) %>%
mutate(diff.rep2.index = max.rep2.index - tsindxr2initial) %>%
mutate(max.rep3.index = pmax(tsindxr3final, tsindxr3initial)) %>%
mutate(diff.rep3.index = max.rep3.index - tsindxr3initial) %>%
mutate(diff.rep1.index = as.numeric(diff.rep1.index)) %>%
mutate(diff.rep2.index = as.numeric(diff.rep2.index)) %>%
mutate(diff.rep3.index = as.numeric(diff.rep3.index)) %>%
rowwise() %>%
mutate(
mean.index = mean(c(diff.rep1.index, diff.rep2.index, diff.rep3.index))
) %>%
filter(is.na(mean.index)) %>%
add_column(
error_type = "TS: Not enough information was available to compute primary outcome for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.13 Flag 25
Primary outcome for the Remote site.
m2qerror25 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(max.rep1.remote = pmax(tsremoter1initial, tsremoter1final)) %>%
mutate(diff.rep1.remote = max.rep1.remote - tsremoter1initial) %>%
mutate(max.rep2.remote = pmax(tsremoter2initial, tsremoter2final)) %>%
mutate(diff.rep2.remote = max.rep2.remote - tsremoter2initial) %>%
mutate(max.rep3.remote = pmax(tsremoter3initial, tsremoter3final)) %>%
mutate(diff.rep3.remote = max.rep3.remote - tsremoter3initial) %>%
mutate(diff.rep1.remote = as.numeric(diff.rep1.remote)) %>%
mutate(diff.rep2.remote = as.numeric(diff.rep2.remote)) %>%
mutate(diff.rep3.remote = as.numeric(diff.rep3.remote)) %>%
rowwise() %>%
mutate(
mean.remote = mean(c(diff.rep1.remote, diff.rep2.remote, diff.rep3.remote))
) %>%
filter(is.na(mean.remote)) %>%
add_column(
error_type = "TS: Not enough information was available to compute primary outcome for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.14 Flag 26
Check if information was available to compute secondary outcome: Mean of 3 Wind-up ratios (WUR) computed ([Max +1]/ [initial +1]). (1 added to handle possibility of zero initial pain rating in denominator). (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions, if a record has < 3 repetitions, it will be flagged
Secondary outcome for the index site
m2qerror26 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(max.rep1.index1 = 1 + (pmax(tsindxr1final, tsindxr1initial))) %>%
mutate(init.rep1.index1 = 1 + (tsindxr1initial)) %>%
mutate(div.rep1.index1 = max.rep1.index1 / init.rep1.index1) %>%
mutate(max.rep2.index1 = 1 + (pmax(tsindxr2final, tsindxr2initial))) %>%
mutate(init.rep2.index1 = 1 + (tsindxr2initial)) %>%
mutate(div.rep2.index1 = max.rep2.index1 / init.rep2.index1) %>%
mutate(max.rep3.index1 = 1 + (pmax(tsindxr3final, tsindxr3initial))) %>%
mutate(init.rep3.index1 = 1 + (tsindxr3initial)) %>%
mutate(div.rep3.index1 = max.rep3.index1 / init.rep3.index1) %>%
rowwise() %>%
mutate(
mean.sec.index = mean(c(div.rep1.index1, div.rep2.index1, div.rep3.index1))
) %>%
filter(is.na(mean.sec.index)) %>%
add_column(
error_type = "TS: Not enough information was available to compute secondary outcome for the index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.10.0.15 Flag 27
Secondary outcome for the Remote site.
m2qerror28 <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(max.rep1.remote1 = 1 + (pmax(tsremoter1initial, tsremoter1final))) %>%
mutate(init.rep1.remote1 = 1 + (tsremoter1initial)) %>%
mutate(div.rep1.remote1 = max.rep1.remote1 / init.rep1.remote1) %>%
mutate(max.rep2.remote1 = 1 + (pmax(tsremoter2initial, tsremoter2final))) %>%
mutate(init.rep2.remote1 = 1 + (tsremoter2initial)) %>%
mutate(div.rep2.remote1 = max.rep2.remote1 / init.rep2.remote1) %>%
mutate(max.rep3.remote1 = 1 + (pmax(tsremoter3initial, tsremoter3final))) %>%
mutate(init.rep3.remote1 = 1 + (tsremoter3initial)) %>%
mutate(div.rep3.remote1 = max.rep3.remote1 / init.rep3.remote1) %>%
rowwise() %>%
mutate(
mean.sec.remote = mean(c(
div.rep1.remote1,
div.rep2.remote1,
div.rep3.remote1
))
) %>%
filter(is.na(mean.sec.remote)) %>%
add_column(
error_type = "TS: Not enough information was available to compute secondary outcome for the remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11 Conditioned Pain Modulation (CPM):
Keep records with “CPM test completed”
m2trcpm.complete <- thor_qst %>%
filter(qst_mcc1_v03_complete == 2) %>%
filter(!is.na(cpmcompleteyn) & cpmcompleteyn != 0)H.2.11.0.1 Flag 28:
Check if water temperature was not checked:
m2qerror28 <- m2trcpm.complete %>%
filter(cpmcoldwatertemp != 1) %>%
add_column(error_type = "CPM: Water temperature not checked") %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.2 Flag 29:
Check for missing or mismatch in cold water pain ratings at 30 seconds.
m2qerror29 <- m2trcpm.complete %>%
filter(
cpmbathrangeyn == 1 | (cpmbathrangeyn == 2 & cpmoutrangetime >= 30)
) %>%
mutate(diff_30 = cpmcoldwaterpain30 - cpmcoldwaterpain30_d) %>%
filter(diff_30 != 0 | is.na(diff_30)) %>%
add_column(
error_type = "CPM: Missing or mismatch in cold water pain ratings at 30 sec"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.3 Flag 30:
Check for missing or mismatch in cold water pain ratings at 60 seconds.
m2qerror30 <- m2trcpm.complete %>%
filter(
cpmbathrangeyn == 1 | (cpmbathrangeyn == 2 & cpmoutrangetime >= 60)
) %>%
mutate(diff_60 = cpmcoldwaterpain60 - cpmcoldwaterpain60_d) %>%
filter(diff_60 != 0 | is.na(diff_60)) %>%
add_column(
error_type = "CPM: Missing or mismatch in cold water pain ratings at 60 sec"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.4 Flag 31:
Check for missing or mismatch in PPT ratings for Remote site (repetition 1).
m2qerror31 <- m2trcpm.complete %>%
mutate(diff_cpm1 = cpmpptremr1val - cpmpptremr1val_d) %>%
filter(diff_cpm1 != 0 | is.na(diff_cpm1)) %>%
add_column(
error_type = "CPM PPT Rep1:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.5 Flag 32:
Check for missing or mismatch in PPT ratings for Remote site (repetition 2).
m2qerror32 <- m2trcpm.complete %>%
mutate(diff_cpm2 = cpmpptremr2val - cpmpptremr2val_d) %>%
filter(diff_cpm2 != 0 | is.na(diff_cpm2)) %>%
add_column(
error_type = "CPM PPT Rep2:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.6 Flag 33:
Check for missing or mismatch in PPT ratings for Remote site (repetition 3).
m2qerror33 <- m2trcpm.complete %>%
mutate(diff_cpm3 = cpmpptremr3val - cpmpptremr3val_d) %>%
filter(diff_cpm3 != 0 | is.na(diff_cpm3)) %>%
add_column(
error_type = "CPM PPT Rep3:Missing or mismatch in PPT ratings for Remote site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.7 Flag 34:
Check if information was available to compute primary outcome (A2CPS MOP v.3.0, pg. 159) i.e. [(pre hand immersion PPT-post immersion PPT)/pre immersion PPT] *100
m2qerror34 <- m2trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremoter1val, pptremoter2val, pptremoter3val))) %>%
rowwise() %>%
mutate(
mean_post = mean(c(cpmpptremr1val, cpmpptremr2val, cpmpptremr3val))
) %>%
mutate(cpm_change = ((mean_pre - mean_post) / mean_pre) * 100) %>%
filter(is.na(cpm_change)) %>%
add_column(
error_type = "CPM: Not enough information to compute primary outcome"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.8 Flag 35:
Check if information was available to compute secondary outcome (A2CPS MOP v.3.0, pg. 159) i.e. CPM difference score computed as pre hand immersion PPT-post immersion PPT
m2qerror35 <- m2trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremoter1val, pptremoter2val, pptremoter3val))) %>%
rowwise() %>%
mutate(
mean_post = mean(c(cpmpptremr1val, cpmpptremr2val, cpmpptremr3val))
) %>%
mutate(cpm_diff = mean_pre - mean_post) %>%
filter(is.na(cpm_diff)) %>%
add_column(
error_type = "CPM: Not enough information to compute secondary outcome"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.11.0.9 Flag 36:
Check If personalized pressure was performed during imaging and there were missing values for cuff Pressure to achieve 4/10 pain outside of scanner during QST as well as missing values for recalibration pressure during imaging.
m2qerror36 <- thor_qst %>%
mutate(
no.qst = case_when(
is.na(fmricuffcalfpressurerecal) & is.na(cuffpfmripressure) ~ 1,
TRUE ~ 0
)
) %>%
mutate(
personal.cuff = case_when(
fmricuffcompletescl == 1 | fmricuffipyn == 1 ~ 1,
TRUE ~ 0
)
) %>%
filter(personal.cuff == 1 & no.qst == 1) %>%
add_column(
error_type = "QST: Missing values for cuff Pressure to achieve 4/10 pain outside of scanner during QST as well as missing values for recalibration pressure during imaging"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12 Dynamic Mechanical Allodynia (DMA)
Keep records with “DMA test completed”
m2dma.baseline <- thor_qst %>%
filter(!is.na(dmatestcompyn) & dmatestcompyn != 0)H.2.12.0.1 Flag 37:
If DMA was performed on both or either site but “DMA complete” was missing.
m2qerror37 <- m2dma.baseline %>%
filter(is.na(dmatestcompyn)) %>%
filter(
!is.na(
dmacontr1pain &
dmacontr1pain_d &
dmacontr2pain &
dmacontr2pain_d &
dmacontr3pain &
dmacontr3pain_d &
dmacontr4pain &
dmacontr4pain_d &
dmacontr5pain &
dmacontr5pain_d |
dmaindxr1pain &
dmaindxr1pain_d &
dmaindxr2pain &
dmaindxr2pain_d &
dmaindxr3pain &
dmaindxr3pain_d &
dmaindxr4pain &
dmaindxr4pain_d &
dmaindxr5pain &
dmaindxr5pain_d &
dmasenscompare
)
) %>%
add_column(
error_type = "DMA:DMA was performed on both or either site but DMA complete was missing"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.2 Flag 38:
Check if DMA was performed on all the sites and completion status for Standardized control site (contralateral) and Standardized index site (surgical) was also checked.
m2qerror38 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 & (dmatestcompwhich___1 == 1 | dmatestcompwhich___2 == 1)
) %>%
add_column(
error_type = "DMA:DMA was performed on all the sites and completion status for Standardized control site (contralateral) and Standardized index site (surgical) was also checked"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.3 Flag 39:
Check if DMA was performed on some sites and completion status for Standardized control site (contralateral) and Standardized index site (surgical) was not specified.
m2qerror39 <- m2dma.baseline %>%
filter(
(dmatestcompyn == 2 &
dmatestcompwhich___1 == 0 &
dmatestcompwhich___2 == 0) |
(dmatestcompyn == 2 &
dmatestcompwhich___1 == 0 &
dmatestcompwhich___2 == 0)
) %>%
add_column(
error_type = "DMA:DMA was performed on some sites and completion status for Standardized control site (contralateral) and Standardized index site (surgical) was not specified"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.4 Flag 40:
Check for mismatch in or missing pain data for Standardized control site (contralateral).
Repetition 1
m2qerror40 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___1 == 1)
) %>%
mutate(dma_stand_cont_diff1 = dmacontr1pain - dmacontr1pain_d) %>%
filter(dma_stand_cont_diff1 != 0 | is.na(dma_stand_cont_diff1)) %>%
add_column(
error_type = "DMA: Repetition 1-Mismatch or missing pain data for standardized control site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.5 Flag 41:
Repetition 2
m2qerror41 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___1 == 1)
) %>%
mutate(dma_stand_cont_diff2 = dmacontr2pain - dmacontr2pain_d) %>%
filter(dma_stand_cont_diff2 != 0 | is.na(dma_stand_cont_diff2)) %>%
add_column(
error_type = "DMA: Repetition 2-Mismatch or missing pain data for standardized control site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.6 Flag 42:
Repetition 3
m2qerror42 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___1 == 1)
) %>%
mutate(dma_stand_cont_diff3 = dmacontr3pain - dmacontr3pain_d) %>%
filter(dma_stand_cont_diff3 != 0 | is.na(dma_stand_cont_diff3)) %>%
add_column(
error_type = "DMA: Repetition 3-Mismatch or missing pain data for standardized control site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.7 Flag 43:
Repetition 4
m2qerror43 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___1 == 1)
) %>%
mutate(dma_stand_cont_diff4 = dmacontr4pain - dmacontr4pain_d) %>%
filter(dma_stand_cont_diff4 != 0 | is.na(dma_stand_cont_diff4)) %>%
add_column(
error_type = "DMA: Repetition 4-Mismatch or missing pain data for standardized control site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.8 Flag 44:
Repetition 5
m2qerror44 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___1 == 1)
) %>%
mutate(dma_stand_cont_diff5 = dmacontr5pain - dmacontr5pain_d) %>%
filter(dma_stand_cont_diff5 != 0 | is.na(dma_stand_cont_diff5)) %>%
add_column(
error_type = "DMA: Repetition 5-Mismatch or missing pain data for standardized control site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.9 Flag 45:
Check for mismatch or missing pain data for standardized index site
Repetition 1
m2qerror45 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___2 == 1)
) %>%
mutate(dma_stand_ind_diff1 = dmaindxr1pain - dmaindxr1pain_d) %>%
filter(dma_stand_ind_diff1 != 0 | is.na(dma_stand_ind_diff1)) %>%
add_column(
error_type = "DMA: Repetition 1-Mismatch or missing pain data for standardized index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.10 Flag 46:
Repetition 2
m2qerror46 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___2 == 1)
) %>%
mutate(dma_stand_ind_diff2 = dmaindxr2pain - dmaindxr2pain_d) %>%
filter(dma_stand_ind_diff2 != 0 | is.na(dma_stand_ind_diff2)) %>%
add_column(
error_type = "DMA: Repetition 2-Mismatch or missing pain data for standardized index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.11 Flag 47:
Repetition 3
m2qerror47 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___2 == 1)
) %>%
mutate(dma_stand_ind_diff3 = dmaindxr3pain - dmaindxr3pain_d) %>%
filter(dma_stand_ind_diff3 != 0 | is.na(dma_stand_ind_diff3)) %>%
add_column(
error_type = "DMA: Repetition 3-Mismatch or missing pain data for standardized index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.12 Flag 48:
Repetition 4
m2qerror48 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___2 == 1)
) %>%
mutate(dma_stand_ind_diff4 = dmaindxr4pain - dmaindxr4pain_d) %>%
filter(dma_stand_ind_diff4 != 0 | is.na(dma_stand_ind_diff4)) %>%
add_column(
error_type = "DMA: Repetition 4-Mismatch or missing pain data for standardized index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.13 Flag 49:
Repetition 5
m2qerror49 <- m2dma.baseline %>%
filter(
dmatestcompyn == 1 | (dmatestcompyn == 2 & dmatestcompwhich___2 == 1)
) %>%
mutate(dma_stand_ind_diff5 = dmaindxr5pain - dmaindxr5pain_d) %>%
filter(dma_stand_ind_diff5 != 0 | is.na(dma_stand_ind_diff5)) %>%
add_column(
error_type = "DMA: Repetition 5-Mismatch or missing pain data for standardized index site"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.14 Flag 50:
Check if both sites were tested and standardized site comparison was not entered
m2qerror50 <- m2dma.baseline %>%
filter(dmatestcompyn == 1 & is.na(dmasenscompare)) %>%
add_column(
error_type = "If both sites were tested and standardized site comparison was not entered"
) %>%
add_column(errors = "error") %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
error_type,
errors
)H.2.12.0.15 QST Biomarkers
H.2.12.0.15.1 PPT Biomarkers:
Mean PPT values at the index site = primary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
primary_ppt_thor <- qdatam2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 3)) %>%
rowwise() %>%
mutate(mean1 = mean(c(pptindxr1val, pptindxr2val, pptindxr3val))) %>%
rename(primary_ppt_thor = mean1) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_ppt_thor
)Mean PPT values at the remote site = secondary data point (A2CPS: Site Manual of Procedures v3.0, pg. 154).
secondary_ppt_thor <- qdatam2 %>%
filter((pptcompleteyn == 1 | pptcompleteyn == 2)) %>%
rowwise() %>%
mutate(mean2 = mean(c(pptremoter1val, pptremoter2val, pptremoter3val))) %>%
rename(secondary_ppt_thor = mean2) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_ppt_thor
)H.2.12.0.15.2 TS Biomarkers:
Primary outcome: Mean of 3 MTS Difference scores computed (Max – initial), (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions.
Primary outcome for the Index site.
primary_ts_index_thor <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(max.rep1.index = pmax(tsindxr1final, tsindxr1initial)) %>%
mutate(diff.rep1.index = max.rep1.index - tsindxr1initial) %>%
mutate(max.rep2.index = pmax(tsindxr2final, tsindxr2initial)) %>%
mutate(diff.rep2.index = max.rep2.index - tsindxr2initial) %>%
mutate(max.rep3.index = pmax(tsindxr3final, tsindxr3initial)) %>%
mutate(diff.rep3.index = max.rep3.index - tsindxr3initial) %>%
mutate(diff.rep1.index = as.numeric(diff.rep1.index)) %>%
mutate(diff.rep2.index = as.numeric(diff.rep2.index)) %>%
mutate(diff.rep3.index = as.numeric(diff.rep3.index)) %>%
rowwise() %>%
mutate(
mean.index = mean(c(diff.rep1.index, diff.rep2.index, diff.rep3.index))
) %>%
rename(primary_ts_index_thor = mean.index) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_ts_index_thor
)Primary outcome for the Remote site.
primary_ts_remote_thor <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(max.rep1.remote = pmax(tsremoter1initial, tsremoter1final)) %>%
mutate(diff.rep1.remote = max.rep1.remote - tsremoter1initial) %>%
mutate(max.rep2.remote = pmax(tsremoter2initial, tsremoter2final)) %>%
mutate(diff.rep2.remote = max.rep2.remote - tsremoter2initial) %>%
mutate(max.rep3.remote = pmax(tsremoter3initial, tsremoter3final)) %>%
mutate(diff.rep3.remote = max.rep3.remote - tsremoter3initial) %>%
mutate(diff.rep1.remote = as.numeric(diff.rep1.remote)) %>%
mutate(diff.rep2.remote = as.numeric(diff.rep2.remote)) %>%
mutate(diff.rep3.remote = as.numeric(diff.rep3.remote)) %>%
rowwise() %>%
mutate(
mean.remote = mean(c(diff.rep1.remote, diff.rep2.remote, diff.rep3.remote))
) %>%
rename(primary_ts_remote_thor = mean.remote) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_ts_remote_thor
)Secondary outcome: Mean of 3 Wind-up ratios (WUR) computed ([Max +1]/ [initial +1]). (1 added to handle possibility of zero initial pain rating in denominator). (A2CPS: Site Manual of Procedures v3.0, pg. 156). This is conditional on having 3 repetitions, if a record has < 3 repetitions, it will be flagged
Secondary outcome for the index site
secondary_ts_index_thor <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 3) %>%
mutate(max.rep1.index1 = 1 + (pmax(tsindxr1final, tsindxr1initial))) %>%
mutate(init.rep1.index1 = 1 + (tsindxr1initial)) %>%
mutate(div.rep1.index1 = max.rep1.index1 / init.rep1.index1) %>%
mutate(max.rep2.index1 = 1 + (pmax(tsindxr2final, tsindxr2initial))) %>%
mutate(init.rep2.index1 = 1 + (tsindxr2initial)) %>%
mutate(div.rep2.index1 = max.rep2.index1 / init.rep2.index1) %>%
mutate(max.rep3.index1 = 1 + (pmax(tsindxr3final, tsindxr3initial))) %>%
mutate(init.rep3.index1 = 1 + (tsindxr3initial)) %>%
mutate(div.rep3.index1 = max.rep3.index1 / init.rep3.index1) %>%
rowwise() %>%
mutate(
mean.sec.index = mean(c(div.rep1.index1, div.rep2.index1, div.rep3.index1))
) %>%
rename(secondary_ts_index_thor = mean.sec.index) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_ts_index_thor
)Secondary outcome for the Remote site.
secondary_ts_remote_thor <- m2tr.complete %>%
filter(tscompleted == 1 | tscompleted == 2) %>%
mutate(max.rep1.remote1 = 1 + (pmax(tsremoter1initial, tsremoter1final))) %>%
mutate(init.rep1.remote1 = 1 + (tsremoter1initial)) %>%
mutate(div.rep1.remote1 = max.rep1.remote1 / init.rep1.remote1) %>%
mutate(max.rep2.remote1 = 1 + (pmax(tsremoter2initial, tsremoter2final))) %>%
mutate(init.rep2.remote1 = 1 + (tsremoter2initial)) %>%
mutate(div.rep2.remote1 = max.rep2.remote1 / init.rep2.remote1) %>%
mutate(max.rep3.remote1 = 1 + (pmax(tsremoter3initial, tsremoter3final))) %>%
mutate(init.rep3.remote1 = 1 + (tsremoter3initial)) %>%
mutate(div.rep3.remote1 = max.rep3.remote1 / init.rep3.remote1) %>%
rowwise() %>%
mutate(
mean.sec.remote = mean(c(
div.rep1.remote1,
div.rep2.remote1,
div.rep3.remote1
))
) %>%
rename(secondary_ts_remote_thor = mean.sec.remote) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_ts_remote_thor
)H.2.12.0.15.3 CPM Biomarkers:
Primary outcome (A2CPS: Site Manual of Procedures v3.0, pg. 159) i.e. [(pre hand immersion PPT-post immersion PPT)/pre immersion PPT] *100
primary_cpm_thor <- m2trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremoter1val, pptremoter2val, pptremoter3val))) %>%
rowwise() %>%
mutate(
mean_post = mean(c(cpmpptremr1val, cpmpptremr2val, cpmpptremr3val))
) %>%
mutate(cpm_change = ((mean_pre - mean_post) / mean_pre) * 100) %>%
rename(primary_cpm_thor = cpm_change) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
primary_cpm_thor
)Secondary outcome (A2CPS: Site Manual of Procedures v3.0, pg. 159) i.e. CPM difference score computed as pre hand immersion PPT-post immersion PPT
secondary_cpm_thor <- m2trcpm.complete %>%
filter(pptcompleteyn == 1 | pptcompleteyn == 2) %>%
rowwise() %>%
mutate(mean_pre = mean(c(pptremoter1val, pptremoter2val, pptremoter3val))) %>%
rowwise() %>%
mutate(
mean_post = mean(c(cpmpptremr1val, cpmpptremr2val, cpmpptremr3val))
) %>%
mutate(cpm_diff = mean_pre - mean_post) %>%
rename(secondary_cpm_thor = cpm_diff) %>%
select(
record_id,
redcap_data_access_group,
redcap_repeat_instrument,
redcap_repeat_instance,
secondary_cpm_thor
)Merge computed biomarkers to the “thor_qst” dataset:
thor_qst <- left_join(
thor_qst,
primary_ppt_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_ppt_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
primary_ts_index_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
primary_ts_remote_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_ts_index_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_ts_remote_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
primary_cpm_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
) %>%
left_join(
.,
secondary_cpm_thor,
by = c(
"record_id",
"redcap_data_access_group",
"redcap_repeat_instrument",
"redcap_repeat_instance"
)
)H.2.12.0.16 New field name(s):
Add field names for the computed biomarkers to the QST data dictionary
# Create field names
primary_ppt_thor_new_row <- data.frame(
field_name = "primary_ppt_thor",
field_type = "numeric",
field_note = "PPT primary biomarker:thor "
)
secondary_ppt_thor_new_row <- data.frame(
field_name = "secondary_ppt_thor",
field_type = "numeric",
field_note = "PPT secondary biomarker:thoracic "
)
primary_ts_index_thor_new_row <- data.frame(
field_name = "primary_ts_index_thor",
field_type = "numeric",
field_note = "TS primary biomarker for the index site:thoracic "
)
primary_ts_remote_thor_new_row <- data.frame(
field_name = "primary_ts_remote_thor",
field_type = "numeric",
field_note = "TS primary biomarker for the remote site:thoracic "
)
secondary_ts_index_thor_new_row <- data.frame(
field_name = "secondary_ts_index_thor",
field_type = "numeric",
field_note = "TS secondary biomarker for the index site:thoracic "
)
secondary_ts_remote_thor_new_row <- data.frame(
field_name = "secondary_ts_remote_thor",
field_type = "numeric",
field_note = "TS secondary biomarker for the remote site:thoracic "
)
primary_cpm_thor_new_row <- data.frame(
field_name = "primary_cpm_thor",
field_type = "numeric",
field_note = "CPM primary biomarker:thoracic "
)
secondary_cpm_thor_new_row <- data.frame(
field_name = "secondary_cpm_thor",
field_type = "numeric",
field_note = "CPM secondary biomarker:thoracic "
)
# Add the new row after the last row
qst_dict <- qst_dict %>%
slice(1:nrow(.)) %>%
add_row(.after = nrow(.), !!!primary_ppt_thor_new_row) %>%
add_row(.after = nrow(.), !!!secondary_ppt_thor_new_row) %>%
add_row(.after = nrow(.), !!!primary_ts_index_thor_new_row) %>%
add_row(.after = nrow(.), !!!primary_ts_remote_thor_new_row) %>%
add_row(.after = nrow(.), !!!secondary_ts_index_thor_new_row) %>%
add_row(.after = nrow(.), !!!secondary_ts_remote_thor_new_row) %>%
add_row(.after = nrow(.), !!!primary_cpm_thor_new_row) %>%
add_row(.after = nrow(.), !!!secondary_cpm_thor_new_row)H.2.12.0.17 Create QST error report for the Thoracotomy cohort.
# Specify the common prefix
m2qst_error <- "m2qerror"
# Find data frames in the global environment with the specified prefix
m2qst_list <- mget(ls(pattern = paste0("^", m2qst_error)))
# Combine the data frames using bind_rows
m2qst_report <- bind_rows(m2qst_list) %>%
as_tibble() %>%
mutate_all(as.character) %>%
pivot_wider(names_from = "error_type", values_from = "errors") %>%
mutate_all(~ replace_na(., ""))m2qst_report %>%
gt() %>%
tab_header(
title = md("**Thoracotomy Cohort QST form Error Report**")
) %>%
tab_options(
table.font.size = px(12),
column_labels.font.size = px(12)
) %>%
tab_style(
style = list(cell_fill(color = "#F4F4F4")),
locations = cells_body(columns = record_id)
)| Thoracotomy Cohort QST form Error Report | |||||||
| record_id | redcap_data_access_group | redcap_repeat_instrument | redcap_repeat_instance | TS: Not enough information was available to compute primary outcome for the index site | TS: Not enough information was available to compute primary outcome for the remote site | TS: Not enough information was available to compute secondary outcome for the index site | CPM: Water temperature not checked |
|---|---|---|---|---|---|---|---|
| 20108 | spectrum_health | qst_mcc1_v03 | 1 | error | error | error | |
| 20133 | university_of_mich | qst_mcc1_v03 | 1 | error | error | ||
| 20337 | university_of_mich | qst_mcc1_v03 | 1 | error | error | ||
| 20028 | university_of_mich | qst_mcc1_v03 | 1 | error | |||
| 20054 | university_of_mich | qst_mcc1_v03 | 1 | error | |||
| 20144 | university_of_mich | qst_mcc1_v03 | 2 | error | |||
H.2.12.0.18 Save:
Save “thor_qst” and data dictionary as .csv files in the folder named “reformatted_QST”
write_csv(
thor_qst,
file = here::here("data", "qst", "Reformatted", "reformatted_thor_qst.csv")
)
write_csv(
qst_dict,
file = here::here("data", "qst", "Reformatted", "updated_qst_dict.csv")
)