Purpose. This script tracks the steps / presents the code used to identify matched participants for the purposes of RISH harmonization.
Written: 2019-12-20
Last ran: 2019-12-23
Website: http://rpubs.com/navona/RISH_matching
#load libraries
library(dplyr)
library(kableExtra)
library(knitr)
library(reshape2)
library(tableone)
library(MatchIt)
xfun::pkg_load2(c('base64enc', 'htmltools', 'mime'))
#read csv
df <- read.csv('../data/SPINS-MRI_2019-12-22.txt', header=FALSE, stringsAsFactors=FALSE) #ls of file system
df_demo <- read.csv('../data/SPINS_DATA_2019-11-23.csv') #demographic (REDCap) data
df_phantomIDs <- read.csv('../data/human-phantom-ids.csv', stringsAsFactors = FALSE)
#first, cut out the name of the containing directory
df <- df %>% filter(!grepl('/archive/data/SPINS/data/nii/', V1))
#make a new variable with separate subject ID
df$record_id <- substr(df$V1, 1, 14)
#make a new variable with separate site
df$site <- substr(df$V1, 7, 9)
#cut out all rows with 'PHA' in ID (these are non-human phantoms)
df <- df %>% filter(!grepl('PHA', record_id))
#take a look at site
table(df$site)
df <- df %>% filter(!grepl('log', record_id)) #remove error log - follow up
#count unique IDs
length(unique(df$record_id)) #483, INCLUDING travelling human phantoms -- should have similar when keep only DWI scans
#keep only DWI scans (includes .nii, bvec, bval, and json)
df <- df %>% filter(grepl('DTI', V1))
#make sure all participants have all 4 data types (.nii, bvec, bval, json)
counts <- as.data.frame(table(df$record_id))
min(counts$Freq) #great -- we have none less than 4, meaning no data is missing
#now, for ease of counting, keep only .nii data in df
df <- df %>% filter(grepl('.nii.gz', V1)) #now, 480 (so 3 missing DWI), but includes human phantoms
#count how many scans from human phantoms - have P as 4th last character
sum(substr(df$record_id, 11, 11) %in% "P") #32
#make a column that indicates if the participant is a human phantom
df$isPhantom <- grepl("P", substr(df$record_id, 11, 11))
#remove test subjects -- not real phantoms
df <- df %>% filter(!grepl('998', record_id))
df <- df %>% filter(!grepl('999', record_id)) #so, we really have 30 'true' phantoms
#for now, split the human phantoms and study participants up, into separate databases
df_phantoms <- df[df$isPhantom == 'TRUE', ]
df <- df[df$isPhantom == 'FALSE', ]
Step 1. Munging DWI data (study participants and human phantoms).
First, we summarize the data available in the archive/SPINS/data/nii
directory. We have DWI data from 476 participants, including 446 unique study participants, and 30 total human phantom scans (across 5 unique human phantoms). The summary of complete DWI participant data (not including human phantoms) per site is as follows:
table_step1 <- t(data.frame(unclass(table(df$site))))
table_step1 %>% kable(row.names=FALSE) %>% kable_styling()
CMH
|
CMP
|
MRC
|
MRP
|
ZHH
|
ZHP
|
137
|
33
|
67
|
71
|
45
|
93
|
#just keep demo vars we care about
df_demo <- df_demo[, c('record_id', 'redcap_event_name', 'hand_laterality_quotient', 'demo_sex_birth', 'demo_age_study_entry', 'wtar_std_score', 'wtarsum_std', 'term_early_withdraw')]
#make a single WTAR variable (note: two WTAR variables from different sites)
df_demo$wtar_std <- ifelse(is.na(df_demo$wtar_std_score), df_demo$wtarsum_std, df_demo$wtar_std_score)
#remove unneeded WTAR variables
df_demo <- subset(df_demo, select = -c(wtar_std_score, wtarsum_std))
#recode variables for clarity
df_demo$redcap_event_name <- ifelse(df_demo$redcap_event_name == 'case_arm_2', 'SSD', 'HC')
df_demo$demo_sex_birth <- ifelse(df_demo$demo_sex_birth == 1, 'female', 'male')
df_demo$term_early_withdraw <- ifelse(df_demo$term_early_withdraw == 2, 'EXCLUDE', df_demo$term_early_withdraw)
df_demo$term_early_withdraw <- ifelse(df_demo$term_early_withdraw == 8, 'EXCLUDE', df_demo$term_early_withdraw)
#first, remove participants who are not eligible
df_demo <- df_demo %>% filter(!grepl('EXCLUDE', term_early_withdraw)) #55 participants
#remove row if there's an NA value in any variable required for harmonization
df_demo <- df_demo[!is.na(df_demo$demo_sex_birth),] #8
df_demo <- df_demo[!is.na(df_demo$demo_age_study_entry),] #0
df_demo <- df_demo[!is.na(df_demo$wtar_std),] #4
df_demo <- df_demo[!is.na(df_demo$hand_laterality_quotient),] #1
#remove data from people who are not right handed (where right-handed is a laterality quotient of >=.5)
#df_demo <- df_demo[(df_demo$hand_laterality_quotient >= .5),]
#remove data from patients (as matching on basis of HCs only)
df_demo <- df_demo[(df_demo$redcap_event_name != 'SSD'),] #304
#rename variables for clarity
names(df_demo)[names(df_demo) == 'redcap_event_name'] <- 'dx'
names(df_demo)[names(df_demo) == 'demo_sex_birth'] <- 'sex'
names(df_demo)[names(df_demo) == 'demo_age_study_entry'] <- 'age'
names(df_demo)[names(df_demo) == 'hand_laterality_quotient'] <- 'handedness'
#merge with imaging data -- will give final count, with all demo and imaging
df <- merge(df, df_demo, by='record_id')
#for clarity, remove unneeded
df <- subset(df, select = -c(term_early_withdraw, V1, isPhantom))
Step 2. Merging DWI data with RISH matching criteria.
Next, for all participants with DWI, we merge demographic data. We exclude participants who (i) did not continuously meet eligibility criteria throughout the SPINS study, (ii) do not have complete data required for harmonization (age
, sex
, handedness
, WTAR
), and/or (iii) are not HCs. In total, we have 175 participants who meet these criteria, as follows:
|
reference
|
targets
|
|
CMH
|
CMP
|
MRC
|
MRP
|
ZHH
|
ZHP
|
female
|
20
|
10
|
9
|
15
|
9
|
19
|
male
|
26
|
4
|
16
|
17
|
9
|
21
|
Step 3. Selection of human phantom scans.
Recall that the Karayumak paper recommends a minimum of n=16 matched controls (n=20 is the “gold standard”). Here, we see that we still have relatively small numbers of participants – for the purposes of matching – at some sites (namely CMP, MRC, and ZHH), exemplified by an unmatched site total n, stratified by sex, that is not much larger than the desired matched site total n, stratefied by sex (i.e., n=8 for “minimum”" matching sample; n=10 for “gold standard” matching sample). Matching under such conditions may still be possible, but not ideal, i.e., it could result in comparatively large distances between matched subjects.
We have decided to mitigate the danger of a poorly matched sample by matching on the “minimum” recommendation of n=16 . Additionally, we will supplement our study sample with available human phantom data, i.e., data from the 3 PIs who were scanned across sites. (Note that the 3 PI scans come from some combination of Aristotle, Bob, Anil, and Miklos, and we cannot use the data from Jessica as she was only scanned at one site (MRC), and did not complete the DWI scan.) Thus, all human phantom data derives from males.
Below, we match human phantom scans on the basis of availability and scan date. Note that there are multiple human phantom scans for the reference site (CMH); when this is also true for a given target site, we include the scans closest in time to the reference site, and/or in the middle of the study. Thus, the human phantom data that we will include is as follows:
#modify the phantom names to include timepoint information
df_phantoms$timepoint <- substr(df_phantoms$V1, 1, 17)
#merge with the phantoms df taken from the archive -- this will get rid of IDs that don't have diffusion data
df_phantoms <- merge(df_phantomIDs, df_phantoms, by.x='record_id', by.y='timepoint')
#remove variables we don't want
df_phantoms <- subset(df_phantoms, select = -c(V1, record_id.y, isPhantom))
#CMH and CMP (Anil not scanned at CMP -- so Miklos)
phantoms_cmp <- df_phantoms[df_phantoms$site == 'CMP',]
phantoms_cmp <- rbind(phantoms_cmp, df_phantoms[c(3, 6, 9),])
#CMH and MRC
phantoms_mrc <- df_phantoms[c(14, 16, 18, 2, 5, 8),]
#CMH and MRP (Bob didn't get scanned at MRP -- so Miklos)
phantoms_mrp <- df_phantoms[df_phantoms$site == 'MRP',]
phantoms_mrp <- rbind(phantoms_mrp, df_phantoms[c(3, 9, 6),])
#CMH and ZHH
phantoms_zhh <- df_phantoms[c(22, 24, 26, 1, 4, 7),]
#CMH and ZHP (Anil didn't get scanned)
phantoms_zhp <- df_phantoms[df_phantoms$site == 'ZHP',]
phantoms_zhp <- rbind(phantoms_zhp, df_phantoms[c(3, 6, 9),])
#write a function to reshape the phantom dfs
phantomsReshape_fn <- function(df){
reshape(df, idvar = 'PI', direction='wide', timevar = 'site')
}
#reshape all dfs
phantoms_cmp <- phantomsReshape_fn(phantoms_cmp)
phantoms_mrc <- phantomsReshape_fn(phantoms_mrc)
phantoms_mrp <- phantomsReshape_fn(phantoms_mrp)
phantoms_zhh <- phantomsReshape_fn(phantoms_zhh)
phantoms_zhp <- phantomsReshape_fn(phantoms_zhp)
#write a function to create table
phantomsTable_fn <- function(df){
df[, c(1, 4, 2)] %>%
kable(row.names=FALSE,
align='c',
col.names = c("PI", 'reference scan', 'target scan')) %>%
kable_styling()
}
CMP
phantomsTable_fn(phantoms_cmp)
PI
|
reference scan
|
target scan
|
Aristotle
|
SPN01_CMH_P001_03
|
SPN01_CMP_P001_04
|
Miklos
|
SPN01_CMH_P002_03
|
SPN01_CMP_P002_04
|
Bob
|
SPN01_CMH_P003_03
|
SPN01_CMP_P003_04
|
MRC
phantomsTable_fn(phantoms_mrc)
PI
|
reference scan
|
target scan
|
Aristotle
|
SPN01_CMH_P001_02
|
SPN01_MRC_P001_02
|
Anil
|
SPN01_CMH_P002_02
|
SPN01_MRC_P002_02
|
Bob
|
SPN01_CMH_P003_02
|
SPN01_MRC_P003_02
|
MRP
phantomsTable_fn(phantoms_mrp)
PI
|
reference scan
|
target scan
|
Aristotle
|
SPN01_CMH_P001_03
|
SPN01_MRP_P001_03
|
Bob
|
SPN01_CMH_P003_03
|
SPN01_MRP_P003_03
|
Miklos
|
SPN01_CMH_P002_03
|
SPN01_MRP_P005_03
|
ZHH
phantomsTable_fn(phantoms_zhh)
PI
|
reference scan
|
target scan
|
Aristotle
|
SPN01_CMH_P001_01
|
SPN01_ZHH_P001_01
|
Anil
|
SPN01_CMH_P002_01
|
SPN01_ZHH_P002_01
|
Bob
|
SPN01_CMH_P003_01
|
SPN01_ZHH_P003_01
|
ZHP
phantomsTable_fn(phantoms_zhp)
PI
|
reference scan
|
target scan
|
Aristotle
|
SPN01_CMH_P001_03
|
SPN01_ZHP_P001_03
|
Miklos
|
SPN01_CMH_P002_03
|
SPN01_ZHP_P002_03
|
Bob
|
SPN01_CMH_P003_03
|
SPN01_ZHP_P003_03
|
Step 4. Review study participants’ data before matching.
Here, we review study participants’ data before matching. We see that differences exist in some variables between sites (note p values); this is just a descriptive look at the data for our own understanding of it.
#make a new, boolean group variable (requires by MatchIt package)
df$group <- ifelse(df$site == 'CMH', 0, 1) #make sure not a factor
#make subsets of df , as is required by MatchIt
df_CMH <- df[df$site == 'CMH', ]
df_CMP <- df[df$site == 'CMH' | df$site == 'CMP', ]
df_MRC <- df[df$site == 'CMH' | df$site == 'MRC', ]
df_MRP <- df[df$site == 'CMH' | df$site == 'MRP', ]
df_ZHH <- df[df$site == 'CMH' | df$site == 'ZHH', ]
df_ZHP <- df[df$site == 'CMH' | df$site == 'ZHP', ]
#review of age, sex, and IQ in all sites
dfTable_fn <- function(df){
CreateTableOne(vars = c('age', 'sex', 'handedness', 'wtar_std'),
data = df,
factorVars = 'sex',
strata = 'site')
}
#make a table for each site
prematchCMP <- dfTable_fn(df_CMP)
prematchMRC <- dfTable_fn(df_MRC)
prematchMRP <- dfTable_fn(df_MRP)
prematchZHH <- dfTable_fn(df_ZHH)
prematchZHP <- dfTable_fn(df_ZHP)
#function to print tableone output in df
tableOne_fn <- function(df){
print(df, printToggle=FALSE, noSpaces=TRUE)
}
#use function
prematchCMP <- tableOne_fn(prematchCMP)
prematchMRC <- tableOne_fn(prematchMRC)
prematchMRP <- tableOne_fn(prematchMRP)
prematchZHH <- tableOne_fn(prematchZHH)
prematchZHP <- tableOne_fn(prematchZHP)
#write a function to make table pretty
prematchTable_fn <- function(df){
df %>%
kable(align='c') %>%
kable_styling()
}
CMP
prematchTable_fn(prematchCMP)
|
CMH
|
CMP
|
p
|
test
|
n
|
46
|
14
|
|
|
age (mean (SD))
|
27.17 (8.34)
|
26.64 (4.63)
|
0.821
|
|
sex = male (%)
|
26 (56.5)
|
4 (28.6)
|
0.127
|
|
handedness (mean (SD))
|
0.70 (0.41)
|
0.59 (0.59)
|
0.432
|
|
wtar_std (mean (SD))
|
116.00 (9.07)
|
110.64 (8.72)
|
0.056
|
|
MRC
prematchTable_fn(prematchMRC)
|
CMH
|
MRC
|
p
|
test
|
n
|
46
|
25
|
|
|
age (mean (SD))
|
27.17 (8.34)
|
37.04 (11.14)
|
<0.001
|
|
sex = male (%)
|
26 (56.5)
|
16 (64.0)
|
0.719
|
|
handedness (mean (SD))
|
0.70 (0.41)
|
0.65 (0.32)
|
0.605
|
|
wtar_std (mean (SD))
|
116.00 (9.07)
|
116.28 (9.65)
|
0.904
|
|
MRP
prematchTable_fn(prematchMRP)
|
CMH
|
MRP
|
p
|
test
|
n
|
46
|
32
|
|
|
age (mean (SD))
|
27.17 (8.34)
|
33.50 (11.28)
|
0.006
|
|
sex = male (%)
|
26 (56.5)
|
17 (53.1)
|
0.948
|
|
handedness (mean (SD))
|
0.70 (0.41)
|
0.49 (0.48)
|
0.039
|
|
wtar_std (mean (SD))
|
116.00 (9.07)
|
111.84 (10.91)
|
0.071
|
|
ZHH
prematchTable_fn(prematchZHH)
|
CMH
|
ZHH
|
p
|
test
|
n
|
46
|
18
|
|
|
age (mean (SD))
|
27.17 (8.34)
|
32.61 (9.41)
|
0.027
|
|
sex = male (%)
|
26 (56.5)
|
9 (50.0)
|
0.848
|
|
handedness (mean (SD))
|
0.70 (0.41)
|
0.54 (0.70)
|
0.242
|
|
wtar_std (mean (SD))
|
116.00 (9.07)
|
107.06 (14.91)
|
0.005
|
|
ZHP
prematchTable_fn(prematchZHP)
|
CMH
|
ZHP
|
p
|
test
|
n
|
46
|
40
|
|
|
age (mean (SD))
|
27.17 (8.34)
|
34.90 (10.56)
|
<0.001
|
|
sex = male (%)
|
26 (56.5)
|
21 (52.5)
|
0.876
|
|
handedness (mean (SD))
|
0.70 (0.41)
|
0.75 (0.43)
|
0.626
|
|
wtar_std (mean (SD))
|
116.00 (9.07)
|
114.25 (11.76)
|
0.439
|
|
#write a function to subset each df by sex
dfSex_fn <- function(df, sex){
df[df$sex == sex, ]
}
#run the function
df_CMP.m <- dfSex_fn(df_CMP, 'male')
df_MRC.m <- dfSex_fn(df_MRC, 'male')
df_MRP.m <- dfSex_fn(df_MRP, 'male')
df_ZHH.m <- dfSex_fn(df_ZHH, 'male')
df_ZHP.m <- dfSex_fn(df_ZHP, 'male')
df_CMP.f <- dfSex_fn(df_CMP, 'female')
df_MRC.f <- dfSex_fn(df_MRC, 'female')
df_MRP.f <- dfSex_fn(df_MRP, 'female')
df_ZHH.f <- dfSex_fn(df_ZHH, 'female')
df_ZHP.f <- dfSex_fn(df_ZHP, 'female')
Step 5. Match study participants from each site.
Now, we match study participants from each site. Following the Karayumak paper, we strive for equal sex balance between the matched groups (as we want to avoid sex-bias and privilege easy-to-interpret and consistent sex-constitution) at the cost of not meeting the “gold standard” n=20 sample size. Effectively, this means that we are striving to include 8 male (including 3 male human phantoms) and 8 females in each group.
One exception to the equal sex balance across all sites much be noted: the CMP match is actually comprised of 7 males (including 3 human phantoms) and 4 females. We figured that slight sex imbalance here is preferable to falling short of the minimum matching sample size. Thus, our matches are as follows:
#write a function to display matched participants
matchTable_fn <- function(df){
df %>%
kable(row.names=FALSE,
col.names = c('reference scan', 'target scan')) %>%
kable_styling()
}
CMP males
matchTable_fn(CMP_matched_males)
reference scan
|
target scan
|
SPN01_CMH_0144
|
SPN01_CMP_0188
|
SPN01_CMH_0038
|
SPN01_CMP_0187
|
SPN01_CMH_0004
|
SPN01_CMP_0199
|
SPN01_CMH_0123
|
SPN01_CMP_0216
|
CMP females
reference scan
|
target scan
|
SPN01_CMH_0194
|
SPN01_CMP_0219
|
SPN01_CMH_0016
|
SPN01_CMP_0193
|
SPN01_CMH_0159
|
SPN01_CMP_0183
|
SPN01_CMH_0028
|
SPN01_CMP_0202
|
SPN01_CMH_0093
|
SPN01_CMP_0218
|
SPN01_CMH_0069
|
SPN01_CMP_0206
|
SPN01_CMH_0026
|
SPN01_CMP_0190
|
SPN01_CMH_0086
|
SPN01_CMP_0209
|
SPN01_CMH_0014
|
SPN01_CMP_0217
|
MRC males
reference scan
|
target scan
|
SPN01_CMH_0008
|
SPN01_MRC_0058
|
SPN01_CMH_0135
|
SPN01_MRC_0036
|
SPN01_CMH_0091
|
SPN01_MRC_0043
|
SPN01_CMH_0015
|
SPN01_MRC_0071
|
SPN01_CMH_0123
|
SPN01_MRC_0016
|
MRC females
reference scan
|
target scan
|
SPN01_CMH_0017
|
SPN01_MRC_0070
|
SPN01_CMH_0069
|
SPN01_MRC_0020
|
SPN01_CMH_0026
|
SPN01_MRC_0068
|
SPN01_CMH_0134
|
SPN01_MRC_0057
|
SPN01_CMH_0054
|
SPN01_MRC_0065
|
SPN01_CMH_0020
|
SPN01_MRC_0066
|
SPN01_CMH_0159
|
SPN01_MRC_0024
|
SPN01_CMH_0125
|
SPN01_MRC_0021
|
MRP males
reference scan
|
target scan
|
SPN01_CMH_0091
|
SPN01_MRP_0137
|
SPN01_CMH_0144
|
SPN01_MRP_0100
|
SPN01_CMH_0044
|
SPN01_MRP_0088
|
SPN01_CMH_0149
|
SPN01_MRP_0095
|
SPN01_CMH_0113
|
SPN01_MRP_0144
|
MRP females
reference scan
|
target scan
|
SPN01_CMH_0016
|
SPN01_MRP_0122
|
SPN01_CMH_0086
|
SPN01_MRP_0123
|
SPN01_CMH_0069
|
SPN01_MRP_0076
|
SPN01_CMH_0007
|
SPN01_MRP_0082
|
SPN01_CMH_0023
|
SPN01_MRP_0139
|
SPN01_CMH_0026
|
SPN01_MRP_0127
|
SPN01_CMH_0005
|
SPN01_MRP_0081
|
SPN01_CMH_0125
|
SPN01_MRP_0156
|
ZHH males
reference scan
|
target scan
|
SPN01_CMH_0119
|
SPN01_ZHH_0056
|
SPN01_CMH_0040
|
SPN01_ZHH_0048
|
SPN01_CMH_0044
|
SPN01_ZHH_0029
|
SPN01_CMH_0031
|
SPN01_ZHH_0008
|
SPN01_CMH_0113
|
SPN01_ZHH_0005
|
ZHH females
reference scan
|
target scan
|
SPN01_CMH_0020
|
SPN01_ZHH_0011
|
SPN01_CMH_0028
|
SPN01_ZHH_0001
|
SPN01_CMH_0159
|
SPN01_ZHH_0002
|
SPN01_CMH_0134
|
SPN01_ZHH_0023
|
SPN01_CMH_0086
|
SPN01_ZHH_0010
|
SPN01_CMH_0026
|
SPN01_ZHH_0003
|
SPN01_CMH_0194
|
SPN01_ZHH_0060
|
SPN01_CMH_0054
|
SPN01_ZHH_0009
|
ZHP males
reference scan
|
target scan
|
SPN01_CMH_0120
|
SPN01_ZHP_0170
|
SPN01_CMH_0123
|
SPN01_ZHP_0120
|
SPN01_CMH_0091
|
SPN01_ZHP_0138
|
SPN01_CMH_0135
|
SPN01_ZHP_0137
|
SPN01_CMH_0065
|
SPN01_ZHP_0167
|
ZHP females
reference scan
|
target scan
|
SPN01_CMH_0017
|
SPN01_ZHP_0149
|
SPN01_CMH_0026
|
SPN01_ZHP_0116
|
SPN01_CMH_0134
|
SPN01_ZHP_0142
|
SPN01_CMH_0069
|
SPN01_ZHP_0074
|
SPN01_CMH_0054
|
SPN01_ZHP_0068
|
SPN01_CMH_0086
|
SPN01_ZHP_0141
|
SPN01_CMH_0109
|
SPN01_ZHP_0108
|
SPN01_CMH_0066
|
SPN01_ZHP_0145
|
Step 6. Review matched study participants from each site.
Here, we are reviewing the characteristics of the matched SPINS sample. Note that data from the 3 male human phantoms is not represented here: this summary is simply of the study participants included in the matched sample. We see that differences that existed in the unmatched sample summarized in Step 4 (namely differences in age, sex, and WTAR score) have disappeared from the matched sample. We also see relatively stable ‘distance’ calculations between site pairings. We also know a priori that, if data from the 3 male phantoms were represeted here, match quality would only improve.
#bind together dfs
df_CMP <- rbind(df_CMP.m, df_CMP.f)
df_MRC <- rbind(df_MRC.m, df_MRC.f)
df_MRP <- rbind(df_MRP.m, df_MRP.f)
df_ZHH <- rbind(df_ZHH.m, df_ZHH.f)
df_ZHP <- rbind(df_ZHP.m, df_ZHP.f)
#function for tables
dfTableMatch_fn <- function(df){
CreateTableOne(vars = c('age', 'sex', 'handedness', 'wtar_std', 'distance'),
data = df,
factorVars = 'sex',
strata = 'site')
}
#run function
df_CMP <- dfTableMatch_fn(df_CMP)
df_MRC <- dfTableMatch_fn(df_MRC)
df_MRP <- dfTableMatch_fn(df_MRP)
df_ZHH <- dfTableMatch_fn(df_ZHH)
df_ZHP <- dfTableMatch_fn(df_ZHP)
#make sure can send to kable
df_CMP <- print(df_CMP, printToggle=FALSE, noSpaces=TRUE)
df_MRC <- print(df_MRC, printToggle=FALSE, noSpaces=TRUE)
df_MRP <- print(df_MRP, printToggle=FALSE, noSpaces=TRUE)
df_ZHH <- print(df_ZHH, printToggle=FALSE, noSpaces=TRUE)
df_ZHP <- print(df_ZHP, printToggle=FALSE, noSpaces=TRUE)
CMP
kable(df_CMP, align='c') %>% kable_styling()
|
CMH
|
CMP
|
p
|
test
|
n
|
13
|
13
|
|
|
age (mean (SD))
|
27.54 (9.27)
|
26.77 (4.80)
|
0.793
|
|
sex = female (%)
|
9 (69.2)
|
9 (69.2)
|
1.000
|
|
handedness (mean (SD))
|
0.67 (0.52)
|
0.69 (0.49)
|
0.939
|
|
wtar_std (mean (SD))
|
113.23 (10.64)
|
110.23 (8.94)
|
0.444
|
|
distance (mean (SD))
|
0.33 (0.18)
|
0.34 (0.19)
|
0.850
|
|
MRC
kable(df_MRC, align='c') %>% kable_styling()
|
CMH
|
MRC
|
p
|
test
|
n
|
13
|
13
|
|
|
age (mean (SD))
|
34.85 (10.89)
|
39.23 (13.57)
|
0.373
|
|
sex = female (%)
|
8 (61.5)
|
8 (61.5)
|
1.000
|
|
handedness (mean (SD))
|
0.73 (0.39)
|
0.77 (0.16)
|
0.712
|
|
wtar_std (mean (SD))
|
114.46 (8.73)
|
112.77 (11.73)
|
0.680
|
|
distance (mean (SD))
|
0.40 (0.28)
|
0.53 (0.29)
|
0.280
|
|
MRP
kable(df_MRP, align='c') %>% kable_styling()
|
CMH
|
MRP
|
p
|
test
|
n
|
13
|
13
|
|
|
age (mean (SD))
|
29.08 (8.75)
|
30.69 (10.38)
|
0.672
|
|
sex = female (%)
|
8 (61.5)
|
8 (61.5)
|
1.000
|
|
handedness (mean (SD))
|
0.63 (0.59)
|
0.69 (0.34)
|
0.760
|
|
wtar_std (mean (SD))
|
117.69 (6.93)
|
113.38 (8.43)
|
0.168
|
|
distance (mean (SD))
|
0.36 (0.25)
|
0.42 (0.26)
|
0.556
|
|
ZHH
kable(df_ZHH, align='c') %>% kable_styling()
|
CMH
|
ZHH
|
p
|
test
|
n
|
13
|
13
|
|
|
age (mean (SD))
|
29.62 (8.78)
|
29.77 (8.41)
|
0.964
|
|
sex = female (%)
|
8 (61.5)
|
8 (61.5)
|
1.000
|
|
handedness (mean (SD))
|
0.66 (0.52)
|
0.47 (0.74)
|
0.457
|
|
wtar_std (mean (SD))
|
114.69 (9.64)
|
107.08 (14.14)
|
0.122
|
|
distance (mean (SD))
|
0.28 (0.15)
|
0.41 (0.31)
|
0.179
|
|
ZHP
kable(df_ZHP, align='c') %>% kable_styling()
|
CMH
|
ZHP
|
p
|
test
|
n
|
13
|
13
|
|
|
age (mean (SD))
|
31.85 (12.54)
|
36.08 (13.34)
|
0.413
|
|
sex = female (%)
|
8 (61.5)
|
8 (61.5)
|
1.000
|
|
handedness (mean (SD))
|
0.59 (0.58)
|
0.72 (0.52)
|
0.532
|
|
wtar_std (mean (SD))
|
115.92 (8.89)
|
115.38 (8.84)
|
0.878
|
|
distance (mean (SD))
|
0.50 (0.27)
|
0.57 (0.27)
|
0.487
|
|
Step 7. Combine all matches – study participants and human phantoms – into a single dataframe for download.
Here, the human phantom pairings are added to the participant matches. As desired, we have n=16 matches for each site. At all sites except CMP, we have an equal sex constitution of n=8 males (including 3 human phantoms) and n=8 females. At CMP, we have n=7 males (including 3 human phantoms) and n=9 females.
males <- rbind(CMP_matched_males,
MRC_matched_males,
MRP_matched_males,
ZHH_matched_males,
ZHP_matched_males)
phantoms_cmp <- phantoms_cmp[,c(4, 2)]
phantoms_mrc <- phantoms_mrc[,c(4, 2)]
phantoms_mrp <- phantoms_mrp[,c(4, 2)]
phantoms_zhh <- phantoms_zhh[,c(4, 2)]
phantoms_zhp <- phantoms_zhp[,c(4, 2)]
#bind phantoms
phantoms <- (mapply(c, phantoms_cmp, phantoms_mrc, phantoms_mrp , phantoms_zhh, phantoms_zhp))
phantoms <- as.data.frame(phantoms)
phantoms[] <- lapply(phantoms, as.character)
#females
females <- rbind(CMP_matched_females,
MRC_matched_females,
MRP_matched_females,
ZHH_matched_females,
ZHP_matched_females)
#bind all together
df_matchComplete <- mapply(c, males, phantoms, females)
#write.csv
write.csv(df_matchComplete, '../data/df_matchComplete.csv', row.names=FALSE)
#link for download
xfun::embed_file('../data/df_matchComplete.csv')
Download df_matchComplete.csv