SM.Rmd 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. ---
  2. title: Supplementary Materials to Establishing the reliability and validity of measures extracted from long-form recordings
  3. output:
  4. pdf_document:
  5. toc: yes
  6. toc_depth: 3
  7. html_document:
  8. toc: yes
  9. toc_depth: '3'
  10. df_print: paged
  11. ---
  12. ```{r setup, include=FALSE, eval=TRUE}
  13. knitr::opts_chunk$set(echo = FALSE, warning = FALSE)
  14. set.seed(726282)
  15. library("lme4")
  16. library("performance") # ICC
  17. library("ggplot2")
  18. library("ggthemes")
  19. library("ggpubr")
  20. library("kableExtra")
  21. library("psych")
  22. library("dplyr")
  23. library("tidyr")
  24. library("stringr")
  25. library("car")
  26. library("ggbeeswarm")
  27. cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
  28. # List of corpora we are interested in
  29. corpora <- c('bergelson', 'lucid', 'winnipeg', 'warlaumont','cougar','fausey-trio')
  30. # Columns that should not be scaled or taken into account as metrics
  31. no.scale.columns <- c('experiment', 'session_id', 'child_id','child_id_unique','age_s', 'nobs', 'nchi',
  32. 'date_iso', 'child_dob', 'missing_audio',"age_bin","duration","usession_id",
  33. "normative","age","duration_alice", "duration_vcm" , "duration_vtc","duration_its" )
  34. data_sets = c('aclew', 'lena')
  35. set.seed(726282)
  36. define_contiguous<-function(mydat){
  37. mydat %>%
  38. #the next line sorts the table by corpus then id then age
  39. arrange(experiment, child_id, age) %>%
  40. #the next line keeps only one line per combination of experiment and child_id
  41. group_by(experiment, child_id) %>%
  42. #the next line, mutate, defines 3 new variables in the dataset, n_rec, age_dist_next_rec, and next_session
  43. mutate( #n_rec = n(), #this var isn't used later
  44. age_dist_next_rec = lead(age) - age,
  45. #this gets the diff corresponding cell in the preceding row and a given row
  46. next_session = lead(usession_id)) %>%
  47. #the next line keeps only recs that are less than 2 months away
  48. filter(age_dist_next_rec<2)
  49. }
  50. get_type<-function(mytab){
  51. temp_tab<-mytab
  52. temp_tab$Type="Output"
  53. temp_tab$Type[grep("fem", temp_tab$met)] <- "Female"
  54. temp_tab$Type[grep("mal", temp_tab$met)] <- "Male"
  55. temp_tab$Type[grep("och", temp_tab$met)] <- "Other children"
  56. temp_tab$Type[grep("adu", temp_tab$met)] <- "Adults"
  57. temp_tab$Type[grep("CTC", temp_tab$met)] <- "Adults"
  58. temp_tab$Type[grep("AWC", temp_tab$met)] <- "Adults"
  59. temp_tab$Type=factor(temp_tab$Type)
  60. temp_tab$Type
  61. }
  62. ```
  63. ## Recalculate everything or not?
  64. If RECALC is set to TRUE, then the ICC tables will be re-generated and the simulation re-ran.
  65. ```{r}
  66. RECALC=FALSE
  67. if(RECALC) source("create-all-icc.R")
  68. if(RECALC) source("simulate-r-for-icc.R")
  69. ```
  70. ## Simulation to better understand ICC
  71. We were uncertain of how to interpret ICC's numeric values. It is described as "proportion of variance explained", but we do not know if it should be considered as a percentage (like R^2) or a correlation (like r). We therefore simulated data controlling the underlying r between paired datapoints to see how ICC recovered that underlying r.
  72. We will inform the simulation by the data we have as follows:
  73. - we'll have the same N of corpora, and of children in each corpus
  74. - we'll have the same metrics for each (i.e., CVC, AWC, etc) -- and these metrics will have the same mean & SD for day 1 of recordings as in observed data
  75. We'll depart from reality as follows:
  76. - we will not consider the r across multiple days observed in the data, but instead generate data points to vary r from a small correlation (r=.1), a moderate one (r=.3), a larger one (r=.5). It is unlikely that test-retest correlations in infancy would be much greater than .5 (based on previous studies using test-retest in experimental tasks), but for completeness, we also use .7 and .9
  77. - we will not consider child age, nor variable re-recording periods
  78. - we will have a single pair of recordings (rather than variable N of re-recordings)
  79. We use simstudy, a package created for such simulations, following the vignette https://cran.r-project.org/web/packages/simstudy/vignettes/correlated.html to create correlated data providing a correlation matrix
  80. In the following plot, each point represents the ICC extracted from a mixed model applied to one metric, combining data from all corpora. It appears that ICC values reflect underlying r values, but underestimating r more the larger r is.
  81. ```{r}
  82. read.csv("../output/df.icc.simu.csv")->df.icc.mixed
  83. plot(df.icc.mixed$icc_child_id~df.icc.mixed$myr)
  84. ```
  85. ## More information for benchmarking our results against previously reported reliability studies
  86. First, we looked for measures of language development used with observational data that can be employed with children aged 0-3 years, and which are available at least in English. All of the instruments we found rely on reports from caregivers, who are basing their judgments on their cumulative experience with the child (e.g., the Child Observation Record Advantage, Schweinhart, McNair, & Larner, 1993; the Desired Results Developmental Profile, REF; the MacArthur-Bates Communicative Development Inventory, REF). Readers are likely most familiar with the MB-CDI, Fenson et al., 1994 report a correlation of r=.95 in their sample of North American, monolingual infants. We did not find a systematic review or meta-analysis providing more such estimates. However, @frank2021 analyzed data archived in a CDI repository, concentrating on American English and Norwegian, where longitudinal data was available. They found that for both datasets, correlations within 2-4 months were above r=.8, with correlations at 16 months of distance (i.e., a form filled in at 8 and 24 months) at their lowest, r=.5. These correlations are very high when considering that the CDI tends to have ceiling and floor effects at these extreme ages. Another report looked at correlations when parents completed two versions of the form in two media (e.g., short form in paper and long form online, or vice versa) within a month. Here, the correlation was r=.8 for comprehension and r=.6 for production. It is worth bearing in mind that test-retest reliability in parental report measures does not depend only on the consistency in the individual infants' ranking for a given behavior, but also on the consistency of the adult in reporting it. Moreover, they are based on cumulative experience, rather than a one-shot observation, as in the case of long-form recordings. Therefore, they do not constitute an appropriate comparison point, and by and large we can be quite certain that they will yield higher reliability than metrics based on the children themselves. For example, a meta-analysis of infant laboratory tasks, including test-retest data for sound discrimination, word recognition, and prosodic processing, found that the meta-analytic weighted average was not different from zero, suggesting that performance in these short laboratory tasks may not be captured in a stable way across testing days. Thus, parental report (or short lab studies) may not be the most appropriate comparisons for our own study.
  87. Second, we did a bibliographic search for systematic reviews of test-retest reliability of standardized instruments to measure language development up to age three years that are available at least in English. Although reliability in these ones may also partially reflect consistency in the adults' reports, they are at least based on a one-shot observation of how the child behaves, rather than the adult's cumulative experience with the child. Note that some promising tests are currently in development or have only recently been released, including the NIH Baby Toolbox (REF) and GSED (REF), and thus we cannot include them in the present summary.
  88. The Ages and Stages Questionnaire (ASQ) is a screening tool to measure infants and children's development based on observation of age-specific behaviors: For instance, at 6 months, in the domain of communication, one of the items asks whether the child smiles. The ASQ's reliability has been the object of a systematic review of independent evidence (Velikonja et al., 2017). Across 10 articles with data from children in the USA, Canada, China, Brazil, India, Chile, the Netherlands, Korea, and Turkey, only three articles reported test-retest correlations, two in the USA (r=.84-1) and one in Turkey (r=.67). However, the meta-analysis authors judged these three studies to be "poor" in quality. Moreover, the ASQ is a questionnaire that an observer fills in, but it can also be administered as a parental questionnaire, reducing its comparability with our purely observational method.
  89. For the other tests, reliability is mainly available from reports by the companies commercializing the test. The Goldman Fristoe Articulation Test – 3rd edition (GFTA-3) (REF) focuses on the ability to articulate certain sounds through picture-based elicitation and can be used from two to five years of age. Available in English and Spanish for a USA context, it has a reported reliability of r=.92 -- although we do not know whether it is this high for two-year-olds specifically. The Preschool Language Scales – 5th edition can be used to measure both comprehension and production from birth to 7 years of age. According to Pearson's report, its test-retest reliability is .86 to .95, depending on the age bracket (0;0-2;11, 3;0-4;11, and 5;0-7;11, 0-7 years). The test has also been adapted to other languages, with good reported test-retest reliability (r=.93; Turkish, Sahli & Belgin, 2017). One issue we see with both of these reports is that children tested varied greatly in age, and the correlation seems to have been calculated based on the raw (rather than the normed) score. As a result, children's ranking may have been stable over test and retest mainly because they varied greatly in age. The Expressive Vocabulary Test – 2nd Edition (EVT-2) is a picture-based elicitation method that can be used with children from 2.5 years of age. The company Springer reports a test-retest reliability of r=.95 by age (REF).
  90. Many other standardized tests exist for children over three years of age. Given that most children included in the present study were under three, these other tests do not constitute an ideal comparison point. Nonetheless, in the spirit of informativeness, it is useful to consider that a systematic review and meta-analysis has been done looking at all psychometric properties (internal consistency, reliability, measurement error, content and structural validity, convergent and discriminant validity) for standardized assessments targeted at children aged 4-12 years (REF). Out of 76 assessments found in the literature, only 15 could be evaluated for their psychometric properties, and 14 reported on reliability based on independent evidence (i.e., the researchers tested and retested children, rather than relying on the company's report of reliability). Among these, correlations for test-retest reliability averaged r=.67, with a range from .35 to .76. The authors concluded that psychometric quality was limited for all assessments, but based on the available evidence, PSL-5 (whose test-retest reliability was r=.69) was among those recommended for use.
  91. Third, and perhaps most relevant, we looked for references that evaluated the psychometric properties of measures extracted from wearable data. We found no previous work attempting to do so on the basis of completely ecological, unconstrained data like ours. The closest references we could find reported on reliability and/or validity of measurements from wearable data collected in constrained situations, such as having 4.5 year old children wear interior sensors and asking them to complete four tests of balance (e.g., standing with their eyes closed; Liu et al., 2022). It is likely that consistency and test-retest reliability are higher in such cases than in data like ours, making it hard to compare. Nonetheless, to give an idea, a recent meta-analysis of wearable inertial sensors in healthy adults found correlations between these instruments and gold standards above r= .88 for one set of measures (based on means) but much lower for another (based on variability, max weighted mean effect r = .58). Regarding test-retest reliability, the meta-analysts report ICCs above .6 for all measures for which they could find multiple studies reporting them. However, those authors point out that the majority of the included studies were classified as low quality, according to a standardized quality assessment for that work.
  92. ## Code to reproduce Table 2
  93. ```{r tab2}
  94. mydat <- read.csv(paste0('../data_output/', 'aclew','_metrics.csv'))
  95. child_per_corpus= aggregate(data = mydat, child_id ~ experiment, function(child_id) length(unique(child_id)))[,2]
  96. rec_per_corpus = aggregate(data = mydat, session_id ~ experiment, function(session_id) length(unique(session_id)))[,2]
  97. rec_per_child = setNames(aggregate(data = mydat, session_id ~ experiment*child_id, function(session_id) length(unique(session_id))), c('experiment', 'Chi', 'No_rec'))
  98. min_rec_per_child = aggregate(data = rec_per_child, No_rec ~ experiment, min)[,2]
  99. max_rec_per_child = aggregate(data = rec_per_child, No_rec ~ experiment, max)[,2]
  100. rec_r_per_child = paste(min_rec_per_child,max_rec_per_child,sep="-")
  101. dur_per_corpus = aggregate(data = mydat, duration_vtc ~ experiment, function(duration_vtc) round(mean(duration_vtc)/3.6e+6,1))[,2]
  102. age_mean_per_corpus = aggregate(data = mydat, age ~ experiment, function(age) round(mean(age),1))[,2]
  103. age_min_per_corpus = aggregate(data = mydat, age ~ experiment, function(age) min(age))[,2]
  104. age_max_per_corpus = aggregate(data = mydat, age ~ experiment, function(age) max(age))[,2]
  105. age_r_per_corpus = paste(age_min_per_corpus,age_max_per_corpus,sep="-")
  106. experiments=c("bergelson", "cougar", "fausey-trio", "lucid", "warlaumont", "winnipeg")
  107. locations=c("Northeast US", "Northwest US", "Western US", "Northwest England", "Western US", "Western Canada")
  108. corpus_description=cbind(experiments,child_per_corpus, rec_per_corpus, rec_r_per_child, dur_per_corpus, age_mean_per_corpus,age_r_per_corpus)
  109. write.csv(corpus_description, "../output/corpus_description.csv", sep='\t')
  110. nkids=length(levels(factor(paste(mydat$experiment,mydat$child_id))))
  111. nrecs=length(levels(factor(paste(mydat$experiment,mydat$session_id))))
  112. ```
  113. ## Code to reproduce Fig. 2
  114. ```{r icc-examples-fig2, echo=F,fig.width=4, fig.height=3,fig.cap="(A) scatterplot for one variable with relatively low ICCs versus (B) one with relatively higher ICCs (see Tables 1-2 for details)"}
  115. # figure of bad ICC: lena avg_voc_dur_chi; good ICC: lena voc_och_ph
  116. data_set="lena"
  117. #mydat <- read.csv(paste0('../data_output/', data_set,'_metrics.csv'))
  118. mydat <- read.csv(paste0('../data_output/', data_set,'_metrics_scaled.csv'))
  119. mydat <- mydat[is.element(mydat$experiment, corpora),]
  120. # remove those data points altogether
  121. mydat <- mydat[!is.na(mydat$avg_voc_dur_chi) & !is.na(mydat$voc_och_ph),]
  122. #make sure cols work as we want them to
  123. mydat$child_id <- paste(mydat$experiment,mydat$child_id)
  124. mydat$unique <- paste(mydat$experiment,mydat$child_id,mydat$session_id)
  125. #sample down to get 2 recs per child
  126. mysample = NULL
  127. for(thischild in levels(as.factor(mydat$child_id))){
  128. onechidat <- mydat[mydat$child_id == thischild,c("child_id","experiment","age","unique","avg_voc_dur_chi","voc_och_ph")]
  129. if(dim(onechidat)[1]>=2){
  130. selrows=sample(1:dim(onechidat)[1],2)
  131. mysample = rbind(mysample,
  132. cbind(onechidat[selrows[1],],
  133. onechidat[selrows[2],c("unique","avg_voc_dur_chi","voc_och_ph")]
  134. )
  135. )
  136. }
  137. }
  138. colnames(mysample) <-
  139. c(
  140. "child_id",
  141. "corpus",
  142. "age",
  143. "unique1",
  144. "avg_voc_dur_chi1",
  145. "voc_och_ph1",
  146. "unique2",
  147. "avg_voc_dur_chi2",
  148. "voc_och_ph2"
  149. )
  150. mysample$corpus = factor(mysample$corpus)
  151. mylimits=range(mysample[,c("avg_voc_dur_chi1","avg_voc_dur_chi2")])
  152. bad <-
  153. ggplot(mysample, aes(avg_voc_dur_chi1, avg_voc_dur_chi2)) +
  154. geom_point(aes(colour = factor(corpus))) +
  155. geom_smooth(method = 'lm', formula = y ~ x) +
  156. labs(color = "Corpus") +
  157. theme(text = element_text(size = 20)) +
  158. theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
  159. panel.background = element_blank(), axis.line = element_line(colour = "black")) +
  160. scale_x_continuous(name="Avg chi voc dur rec 1",limits=mylimits) +
  161. scale_y_continuous(name="Avg chi voc dur rec 2",limits=mylimits) +
  162. geom_abline(intercept = 0, slope = 1)
  163. mylimits=range(mysample[,c("voc_och_ph1","voc_och_ph2")])
  164. good <-
  165. ggplot(mysample, aes(voc_och_ph1, voc_och_ph2)) +
  166. geom_point(aes(colour = factor(corpus))) +
  167. geom_smooth(method = 'lm', formula = y ~ x) +
  168. labs(color = "Corpus") +
  169. theme(text = element_text(size = 20)) +
  170. theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
  171. panel.background = element_blank(), axis.line = element_line(colour = "black")) +
  172. scale_x_continuous(name="N other ch voc rec 1",limits=mylimits) +
  173. scale_y_continuous(name="N other ch voc rec 2",limits=mylimits) +
  174. geom_abline(intercept = 0, slope = 1)
  175. ggarrange(bad, good,
  176. ncol = 2, nrow = 1, common.legend = TRUE, vjust = 1.5, hjust=0,
  177. font.label = list(size = 20)) + labs(color= "Corpus") + theme(text = element_text(size = 20))
  178. ```
  179. ## Code to reproduce other text in the section Results, subsection Overall reliability
  180. ```{r readin}
  181. df.icc.mixed<-read.csv("../output/df.icc.mixed.csv")
  182. df.icc.mixed[df.icc.mixed$formula=="no_exp",c("data_set","metric")]
  183. ```
  184. Out of the `r dim(df.icc.mixed)[1]` fitted models, we could fit `r table(df.icc.mixed$formula)["full"]` with the full model, yielding a measure of Corpus ICC. Of these, `r round(sum(df.icc.mixed$icc_corpus<.2,na.rm=T)/sum(!is.na(df.icc.mixed$icc_corpus))*100)`% had Corpus ICCs smaller than .2, consistent with the idea that LENA and ACLEW metrics are robust to corpus differences. For the `r table(df.icc.mixed$formula)["no_exp"]` for which the full model was singular, we fit the data with the No Corpus model, and none was singular then, yielding Child ICCs for all `r dim(df.icc.mixed)[1]` metrics.
  185. ## Code to reproduce Fig. 4
  186. ```{r icc-allexp-fig4, echo=F,fig.width=4, fig.height=3,fig.cap="Distribution of ICC attributed to corpus (a) and children (b), when combining data from all corpora."}
  187. df.icc.mixed$Type<-get_type(df.icc.mixed)
  188. ggplot(df.icc.mixed, aes(y = icc_child_id, x = toupper(data_set))) +
  189. geom_violin(alpha = 0.5) +
  190. geom_quasirandom(aes(colour = Type,shape = Type)) +
  191. theme() +labs( y = "ICC child ID",x="Pipeline")
  192. ```
  193. ## Code to reproduce text under Figure 4
  194. ```{r reg model icc}
  195. lr_icc_chi <- lm(icc_child_id ~ Type * data_set, data=df.icc.mixed)
  196. #binomial could be used, but diagnostic plots look pretty good (other than some outliers)
  197. reg_sum=summary(lr_icc_chi)
  198. reg_anova=Anova(lr_icc_chi)
  199. ```
  200. ```{r explo-och-sibn}
  201. source("functions.R")
  202. myaclewdat <- read.csv(paste0('../data_output/', "aclew",'_metrics_scaled.csv'))
  203. myaclewdat <- myaclewdat[is.element(myaclewdat$experiment, corpora),]
  204. read.csv("../input/aclew_md.csv")->x
  205. x$labname[x$labname=="ROW"]<-"luc"
  206. x$labname[x$labname=="SOD"]<-"win"
  207. x$ch_id=paste(tolower(x$labname),as.character(x$child_level_id))
  208. x$n_of_siblings<-x$number_older_sibs
  209. x$ch_id[x$labname %in% c("BER")] = paste(tolower(x$labname[x$labname %in% c("BER")]),as.numeric(as.character(x$child_level_id[x$labname %in% c("BER")])))
  210. x=x[!duplicated(x$ch_id),]
  211. myaclewdat$lab=substr(myaclewdat$experiment,1,3)
  212. myaclewdat$ch_id=paste(myaclewdat$lab,gsub(".* ","",myaclewdat$child_id))
  213. myaclewdat$ch_id[myaclewdat$experiment=="warlaumont"]=gsub(" 0"," ",myaclewdat$ch_id[myaclewdat$experiment=="warlaumont"])
  214. myaclewdat$ch_id[myaclewdat$experiment=="winnipeg"]=gsub(" C"," CW",myaclewdat$ch_id[myaclewdat$experiment=="winnipeg"])
  215. #sort(factor(myaclewdat$ch_id[myaclewdat$experiment=="winnipeg"]))
  216. #sort(x$ch_id[x$lab=="win"])
  217. #sum(myaclewdat$ch_id %in% x$ch_id)
  218. #sum(x$ch_id %in% myaclewdat$ch_id)
  219. mydat2=merge(myaclewdat,x[,c("ch_id","n_of_siblings")],all.x=T,by="ch_id")
  220. #table(mydat2$n_of_siblings,mydat2$experiment)
  221. model<-lmer(voc_dur_och_ph~ age_s +n_of_siblings + (1|experiment/child_id),data=mydat2)
  222. #is sing
  223. model<-lmer(voc_dur_och_ph~ age_s +n_of_siblings + (1|child_id),data=mydat2)
  224. icc.result.split<- t(as.data.frame(icc(model, by_group=TRUE))$ICC)
  225. #names(icc.result.split)=c("icc_child_id", "icc_corpus")
  226. names(icc.result.split)=c("icc_child_id")
  227. read.csv("../input/quechua_md.csv")->x
  228. ```
  229. Figure 5 shows the distribution of Child ICC across all 69 metrics, separately for each pipeline. The majority of metrics had Child ICCs between .3 and .5. Seven metrics had Child ICCs higher or equal to .5. Surprisingly, the top 6 metrics in terms of Child ICC corresponded to the "other child" category, reported to have the worst accuracy according to previous analyses (Cristia et al., 2020). In an analysis fully reported in supplementary materials (SM J), we find some evidence that this may be due to the presence versus absence of siblings. The next metric with the highest Child ICC corresponded to an output measure, namely the total vocalization duration per hour extracted from ACLEW annotations, with a Child ICC of .5. Among adult metrics, the average vocalization duration for female vocalizations for ACLEW and the ACLEW equivalent of CTC had the highest Child ICC (.45 and .46, respectively).
  230. Six measures had higher ICCs, and surprisingly, they corresponded to the "other child" category, known to have the worst accuracy according to previous analyses (Cristia et al., 2020). We reasoned this may be because children in our corpora vary in terms of the number of siblings they have, and that siblings' presence may be stable across recordings. To address this possibility, we fit the full model again to predict number of vocalizations from other children, but this time including sibling number as a fixed effect $lmer(metric~ age + sibling_number + (1|corpus/child))$, so that individual variation that was actually due to sibling number was captured by that fixed effect instead of the random effect for child. We did this for the metric with the highest Child ICC, ACLEW's total vocalization duration by other children. Results indicated the full model was singular, a first sign that included variables explained shared variance. When we fitted the No Corpus model, Child ICC was indeed reduced from `r round(df.icc.mixed[df.icc.mixed$metric=="voc_dur_och_ph" & df.icc.mixed$data_set=="aclew","icc_child_id"],2)` to `r round(icc.result.split["icc_child_id"],2)`.
  231. Going back to our overarching analyses, we explored how similar Child ICCs were across different talker types and pipelines. We fit a linear model with the formula lm(icc_child_id ~ type * pipeline), where type indicates whether the measure pertained to the key child, (female/male) adults, other children; and pipeline LENA or ACLEW. We found an adjusted R-squared of `r round(reg_sum$adj.r.squared*100)`%, suggesting much of the variance across Child ICCs was explained by this model. A Type 3 ANOVA on this model revealed only type was a signficant (F(`r reg_anova["Type","Df"]`)=`r round(reg_anova["Type","F value"],1)`, p<.001), whereas neither pipeline nor the interaction between type and pipeline were significant.
  232. ## Code to reproduce Table 3
  233. ```{r tab3, results="as.is"}
  234. key_metrics = c("wc_adu_ph", "lena_CVC", "lena_CTC", "voc_fem_ph", "voc_chi_ph")
  235. x <- merge(df.icc.mixed[df.icc.mixed$metric %in% key_metrics & df.icc.mixed$data_set=="lena",c("metric","icc_child_id")] ,
  236. df.icc.mixed[df.icc.mixed$metric %in% key_metrics & df.icc.mixed$data_set=="aclew",c("metric","icc_child_id")],
  237. by='metric', all=TRUE)
  238. colnames(x) <- c("metric", "LENA ICC", "ACLEW ICC")
  239. rownames(x)<-x$metric
  240. x[,2:3]=round(x[,2:3],2)
  241. x=x[key_metrics,]
  242. kable(x,row.names = F,digits=2,caption="Most commonly used metrics.")
  243. x
  244. ```
  245. ## Code to reproduce "Exploratory analyses: Correlations based on paired analyses of recordings done within two months"
  246. ```{r correlation analysis for close recs, warning = F, echo=FALSE}
  247. #to compare with Gilkerson, we just need to focus on AWC, CVC, CTC (in LENA, but for comparison purposes, we also include aclew)
  248. data_set="lena"
  249. mydat_lena <- read.csv(paste0('../data_output/', data_set,'_metrics_scaled.csv'))
  250. mydat_lena$uchild_id <- paste(mydat_lena$experiment, mydat_lena$child_id)
  251. mydat_lena$usession_id <- paste(mydat_lena$uchild_id, mydat_lena$session_id)
  252. mydat_lena=mydat_lena[order(mydat_lena$experiment,mydat_lena$child_id,mydat_lena$age),]
  253. dist_contig_lena <- define_contiguous(mydat_lena)
  254. mydat_lena = merge(mydat_lena,dist_contig_lena[,c("usession_id","next_session")],by="usession_id",all.x=T)
  255. #summary(dist_contig$n_rec) #distribution of n of recs per child
  256. #table(dist_contig$experiment) #this is the number of eligible recordings per corpus
  257. #sum(table(dist_contig$experiment)) #and overall
  258. #table(dist_contig$experiment[!duplicated(dist_contig$uchild_id)])#this is the number of eligible children per corpus
  259. #sum(table(dist_contig$experiment[!duplicated(dist_contig$uchild_id)])) #and overall
  260. #given those two numbers, with 5 draws we'd cover many combinations in winni, lucid, & trio; but we'll do 10 because there are a lot of recs in cougar & bergelson. Later increased to 20 bc there was a lot of variability still in the average r
  261. mydat_aclew <- read.csv(paste0('../data_output/', "aclew",'_metrics_scaled.csv'))
  262. mydat_aclew$uchild_id <- paste(mydat_aclew$experiment, mydat_aclew$child_id)
  263. mydat_aclew$usession_id <- paste(mydat_aclew$uchild_id, mydat_aclew$session_id)
  264. dist_contig_aclew <- define_contiguous(mydat_aclew)
  265. mydat_aclew = merge(mydat_aclew,dist_contig_aclew[,c("usession_id","next_session")],by="usession_id",all.x=T)
  266. nsamples=20
  267. all_rs=data.frame(matrix(NA,nrow=dim(df.icc.mixed)[1],ncol=(nsamples)))
  268. colnames(all_rs[,1:nsamples])<-paste0("sample",1:nsamples)
  269. all_rs$data_set<-df.icc.mixed$data_set
  270. all_rs$metric<-df.icc.mixed$metric
  271. for(i in 1:nsamples){#i=1
  272. #for each child, sample 2 contiguous recordings that are less than 2 months away
  273. #step 1: sample one session per child among the list of sessions that are close by
  274. #we use the lena one because there is no difference across lena & aclew in terms of which kids have which sessions, since in this paper all recs have both lena and aclew, so it's just a question of using one of them
  275. close_sessions <- dist_contig_lena %>%
  276. group_by(uchild_id)%>%
  277. slice_sample(n = 1)
  278. for(j in 1:dim(df.icc.mixed)[1]){# j=1
  279. data_set=df.icc.mixed[j,"data_set"]
  280. metric=df.icc.mixed[j,"metric"]
  281. if(data_set=="aclew") dat_for_cor<-mydat_aclew else dat_for_cor<-mydat_lena
  282. #step 2: get data from those sampled sessions as rec1
  283. rec1 = subset(dat_for_cor,usession_id %in% close_sessions$usession_id)
  284. #step 3: get the next session
  285. rec2_sessions=levels(factor(rec1$next_session))
  286. rec2 = subset(dat_for_cor,usession_id %in% rec2_sessions)
  287. all_rs[all_rs$data_set==data_set & all_rs$metric==metric,i]<-
  288. cor.test(rec1[,metric],rec2[,metric])$estimate
  289. }
  290. }
  291. #summary(all_rs)
  292. rval_tab=cbind(apply(all_rs[,1:20],1,mean),apply(all_rs[,1:20],1,sd),all_rs[,21:22])
  293. colnames(rval_tab) <-c("m","sd","p","met")
  294. rval_tab[,1:2]=round(rval_tab[,1:2],2)
  295. rval_tab$fin<-paste0(rval_tab$m," ","[",rval_tab$m-2*rval_tab$sd,",",rval_tab$m+2*rval_tab$sd,"]")
  296. mytab=rbind(cbind(rval_tab[rval_tab$p=="aclew" & rval_tab$met== "wc_adu_ph","fin"],rval_tab[rval_tab$p=="lena" & rval_tab$met== "wc_adu_ph","fin"]),
  297. cbind(NA,rval_tab[rval_tab$met== "lena_CVC","fin"]),
  298. cbind(NA,rval_tab[rval_tab$met== "lena_CTC","fin"]),
  299. cbind(rval_tab[rval_tab$p=="aclew" & rval_tab$met== "voc_chi_ph","fin"],rval_tab[rval_tab$p=="lena" & rval_tab$met== "voc_chi_ph","fin"])
  300. )
  301. mytab=gsub("0.",".",mytab,fixed=T)
  302. print(mytab)
  303. ```
  304. ## Code to reproduce Fig. 5
  305. ```{r r-fig5, echo=F,fig.width=4, fig.height=3,fig.cap="Distribution of correlation coefficients."}
  306. rval_tab$Type<-get_type(rval_tab)
  307. ggplot(rval_tab, aes(y = m, x = toupper(p))) +
  308. geom_violin(alpha = 0.5) +
  309. geom_quasirandom(aes(colour = Type,shape = Type)) +
  310. theme() +labs( y = "r",x="Pipeline")
  311. ```
  312. ## Code to reproduce results of regression on correlation values
  313. ```{r reg model cor}
  314. lr_cor <- lm(m ~ Type * p, data=rval_tab)
  315. #plot(lr_cor)
  316. #binomial could be used, but diagnostic plots look great
  317. reg_sum_cor=summary(lr_cor)
  318. reg_anova_cor=Anova(lr_icc_chi)
  319. ```
  320. To see whether correlations in this analysis differed by talker types and pipelines, we fit a linear model with the formula lm(cor ~ type * pipeline), where type indicates whether the measure pertained to the key child, (female/male) adults, other children; and pipeline LENA or ACLEW. We found an adjusted R-squared of `r round(reg_sum_cor$adj.r.squared*100)`%, suggesting this model did not explain a great deal of variance in correlation coefficients. Moreover, a Type 3 ANOVA on this model revealed no significant effects or interactions (all p's > .1).
  321. ```{r print out anova results rec on cor}
  322. kable(reg_anova_cor)
  323. ```
  324. ## Code to reproduce text and figures in "Exploratory analyses: Reliability within corpus"
  325. ```{r read in icc by corpus}
  326. df.icc.corpus<-read.csv("../output/df.icc.corpus.csv")
  327. df.icc.corpus$Type <- get_type(df.icc.corpus)
  328. ```
  329. Figure 5A addresses this question, showing the distribution of ICC across our 53 metrics in each of the `r length(levels(factor(df.icc.corpus$corpus)))` included corpora. Out of `r dim(df.icc.corpus)[1]` fitted models (53 metrics times `r length(levels(factor(df.icc.corpus$corpus)))` corpora), `r sum(df.icc.corpus$formula=="no_chi_effect")` were singular when including a random intercept per child, and therefore they could not be included in these analyses at all, and the remaining `r sum(df.icc.corpus$formula=="no_exp")` were singular when including a random intercept per corpus.
  330. ```{r icc-bycor-fig5A, echo=F,fig.width=4, fig.height=10,fig.cap="Child ICC by metric type and pipeline, when considering each corpus separately."}
  331. ggplot(df.icc.corpus, aes(y = icc_child_id, x = toupper(data_set))) +
  332. geom_violin(alpha = 0.5) +
  333. geom_quasirandom(aes(colour = Type,shape = Type)) +
  334. theme(legend.position = "top", axis.title.y=element_blank() ,axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +labs( y = "ICC child ID",x="Pipeline") +
  335. facet_grid(cols=vars(corpus))
  336. ```
  337. ```{r icc-bycor-fig5B, echo=F,fig.width=4, fig.height=10,fig.cap="Correlations in Child ICC across corpora. Each point indicates the correlation in Child ICC for the corpus named in the x-axis with every other corpus."}
  338. r_X_corpus = NULL
  339. for(corpusA in levels(factor(df.icc.corpus$corpus))){
  340. for(corpusB in levels(factor(df.icc.corpus$corpus))) if(corpusA!=corpusB){
  341. #check:
  342. # print(sum(df.icc.corpus[df.icc.corpus$corpus==corpusA,c("metric","data_set")] == df.icc.corpus[df.icc.corpus$corpus==corpusB,c("metric","data_set")]))
  343. #yes, the metric & data_set are matching across the two
  344. r_X_corpus = rbind(r_X_corpus, cbind(corpusA,corpusB,cor.test(df.icc.corpus$icc_child_id[df.icc.corpus$corpus==corpusA],df.icc.corpus$icc_child_id[df.icc.corpus$corpus==corpusB])$estimate))
  345. }
  346. }
  347. r_X_corpus=data.frame(r_X_corpus)
  348. colnames(r_X_corpus)[3]<-c("cor")
  349. r_X_corpus$cor=as.numeric(as.character(r_X_corpus$cor))
  350. #summary(r_X_corpus$cor) #mean correlation across corpora is zero!
  351. ggplot(r_X_corpus, aes(y = cor, x = corpusA)) +
  352. geom_violin(alpha = 0.5) +
  353. geom_quasirandom() +
  354. theme() +labs( y = "r",x="Corpus")
  355. ```
  356. ```{r reg model corpusm}
  357. cor_icc <- lm(icc_child_id ~ Type * data_set * corpus, data=df.icc.corpus)
  358. #plot(cor_icc)
  359. #binomial could be used, diagnostic plots look okay-ish, inequality of variance with high ICCs being less numerous & less spread out
  360. reg_sum_cor_icc=summary(cor_icc)
  361. reg_anova_cor_icc=Anova(cor_icc)
  362. ```
  363. The fact that we cannot infer reliability from one corpus based on another one was confirmed statistically: We checked whether Child ICC differed by talker types and pipelines across corpora by fitting a linear model with the formula $lm(Child_ICC ~ type * pipeline * corpus)$, where type indicates whether the measure pertained to the key child, (female/male) adults, other children; pipeline LENA or ACLEW; and corpus the corpus ID. We found an adjusted R-squared of `r round(reg_sum_cor_icc$adj.r.squared*100)`%, suggesting this model explained over half of the variance in Child ICC. A Type 3 ANOVA on this model revealed several significant effects and interactions, including a three-way interaction of type, pipeline, and corpus; a two-way interaction of type and corpus; and a main effect of corpus. See the Supplementary Materials for more information.
  364. ```{r print out anova results rec on icc by corpus}
  365. kable(reg_anova_cor_icc)
  366. ```
  367. ## Code to reproduce text and figures in "Exploratory analyses: Reliability across age groups"
  368. ```{r prepAge}
  369. df.icc.age<-read.csv("../output/df.icc.age.csv")
  370. age_levels=c("(0,6]" , "(6,12]", "(12,18]" ,"(18,24]" ,"(24,30]", "(30,36]" )
  371. #not present in data: , "(36,42]", "(42,48]", "(48,54]"
  372. df.icc.age$age_bin<-factor(df.icc.age$age_bin,levels=age_levels)
  373. df.icc.age$Type<-get_type(df.icc.age)
  374. ```
  375. Out of `r dim(df.icc.age)[1]` fitted models (53 metrics times `r length(levels(factor(df.icc.age$age_bin)))` age bins), `r sum(df.icc.age$formula=="no_chi_effect")` were singular when including a random intercept per child, and therefore they could not be included in these analyses at all. In addition, `r sum(df.icc.age$formula=="no_exp")` were singular when including a random intercept per corpus. The remaining `r sum(df.icc.age$formula=="full")` could be analyzed with the full model.
  376. ```{r relBYage-fig6A, echo=F,fig.width=6, fig.height=10,fig.cap="Distribution of ICC attributed to corpus (a) and children (b), when binning children's age."}
  377. #this complicated section is just to add N of participants in each facet, we first estimate it:
  378. facet_labels_chi=facet_labels_cor=NULL
  379. for(thisage in levels(df.icc.age$age_bin)){#thisage="(0,6]"
  380. facet_labels_cor = c(facet_labels_cor,paste0("N cor=",min(df.icc.age$ncor[df.icc.age$age_bin==thisage],na.rm=T))) #checked: there is no variation across metrics in n of corpora included
  381. if(min(df.icc.age$nchi[df.icc.age$age_bin==thisage],na.rm=T) !=max(df.icc.age$nchi[df.icc.age$age_bin==thisage],na.rm=T)){
  382. facet_labels_chi = c(facet_labels_chi,paste0("N chi=",paste(range(df.icc.age$nchi[df.icc.age$age_bin==thisage],na.rm=T),collapse="-")))
  383. } else {
  384. facet_labels_chi = c(facet_labels_chi,paste0("N chi=",min(df.icc.age$nchi[df.icc.age$age_bin==thisage],na.rm=T)))
  385. }
  386. }
  387. #and then we structure it so that it goes on the plot
  388. f_labels<-data.frame(age_bin=levels(df.icc.age$age_bin),facet_labels_chi=facet_labels_chi,facet_labels_cor=facet_labels_cor)
  389. f_labels$age_bin<-factor(f_labels$age_bin,levels=age_levels)
  390. ggplot(df.icc.age, aes(y = icc_child_id, x = toupper(data_set))) +
  391. geom_violin(alpha = 0.5) +
  392. geom_quasirandom(aes(colour = Type,shape = Type)) +
  393. theme(legend.position="none") +labs( y = "r",x="Pipeline") + facet_wrap(~age_bin, ncol = 3) +
  394. geom_text(x=1.5,y=max(df.icc.age$icc_child_id,na.rm=T),aes(label=facet_labels_chi),data=f_labels,size=2) +
  395. geom_text(x=1.5,y=max(df.icc.age$icc_child_id,na.rm=T)*.95,aes(label=facet_labels_cor),data=f_labels,size=2)
  396. ```
  397. ```{r reg model age}
  398. age_icc <- lm(icc_child_id ~ Type * data_set * age_bin, data=df.icc.age)
  399. #plot(age_icc)
  400. #binomial could be used, diagnostic plots look good
  401. reg_sum_age_icc=summary(age_icc)
  402. reg_anova_age_icc=Anova(age_icc)
  403. ```
  404. As we did in the previous section for corpus, we checked whether Child ICC differed by talker types and pipelines across age bins by fitting a linear model with the formula $lm(Child_ICC ~ type * pipeline * age_bin)$. We found an adjusted R-squared of `r round(reg_sum_age_icc$adj.r.squared*100)`%, suggesting this model explained over half of the variance in Child ICC. However, a Type 3 ANOVA on this model revealed only an interaction of type and age bin, as well as a main effect of age bin, suggesting less complex effects than in the case of corpus. See the Supplementary Materials for more information.
  405. ```{r icc-bycor-fig6B, echo=F,fig.width=4, fig.height=4,fig.cap="Correlations in Child ICC across corpora. Each point indicates the correlation in Child ICC for the corpus named in the x-axis with every other corpus."}
  406. r_X_age = NULL
  407. for(ageA in levels(factor(df.icc.age$age_bin))){#ageA="(0,6]"
  408. for(ageB in levels(factor(df.icc.age$age_bin))) if(ageA!=ageB){#ageB="(6,12]"
  409. #check:
  410. # print(sum(df.icc.age[df.icc.age$age_bin==ageA,c("metric","data_set")] == df.icc.age[df.icc.age$age_bin==ageB,c("metric","data_set")]))
  411. #dim(df.icc.age[df.icc.age$age_bin==ageA,c("metric","data_set")])
  412. #yes, the metric & data_set are matching across the two
  413. r_X_age = rbind(r_X_age, cbind(ageA,ageB,cor.test(df.icc.age$icc_child_id[df.icc.age$age_bin==ageA],df.icc.age$icc_child_id[df.icc.age$age_bin==ageB])$estimate))
  414. }
  415. }
  416. r_X_age=data.frame(r_X_age)
  417. colnames(r_X_age)[3]<-c("cor")
  418. r_X_age$cor=as.numeric(as.character(r_X_age$cor))
  419. r_X_age$ageA=factor(r_X_age$ageA,levels=age_levels)
  420. #r_X_age$ageB=factor(r_X_age$ageB,levels=age_levels)
  421. #summary(r_X_age$cor) #mean correlation across corpora is zero!
  422. ggplot(r_X_age, aes(y = cor, x = ageA)) +
  423. geom_violin(alpha = 0.5) +
  424. geom_quasirandom() +
  425. theme() +labs( y = "r",x="Age")
  426. ```
  427. ## Save information about packages used
  428. ```{r}
  429. writeLines(capture.output(sessionInfo()), "sessionInfo.txt")
  430. ```