R/algorithms.R

Defines functions aat_singlemediandiff_older aat_singlemediandiff_old aat_singlemediandiff aat_singlemeandiff_older aat_singlemeandiff_old aat_singlemeandiff aat_standardregression aat_regression aat_dscore_multiblock_old aat_dscore_multiblock aat_mediandscore_older aat_mediandscore_old aat_mediandscore aat_dscore_older aat_dscore_old aat_dscore aat_doublemediandiff_older aat_doublemediandiff_old aat_doublemediandiff aat_doublemeandiff_older aat_doublemeandiff_old aat_doublemeandiff

Documented in aat_doublemeandiff aat_doublemediandiff aat_dscore aat_dscore_multiblock aat_mediandscore aat_regression aat_singlemeandiff aat_singlemediandiff aat_standardregression

# Score computation algorithms ####

#' @title AAT score computation algorithms
#' @name Algorithms
#' @description AAT score computation algorithms
#' @param ds A long-format data.frame
#' @param subjvar Column name of the participant identifier variable
#' @param pullvar Column name of the movement variable (0: avoid; 1: approach)
#' @param targetvar Column name of the stimulus category variable (0: control stimulus; 1: target stimulus)
#' @param rtvar Column name of the reaction time variable
#' @param ... Other arguments passed on by functions (ignored)
#'
#' @return A data.frame containing participant number and computed AAT score.
NULL

#' @describeIn Algorithms computes a mean-based double-difference score:
#' \code{(mean(push_target) - mean(pull_target)) - (mean(push_control) - mean(pull_control))}
#'
#' @export
aat_doublemeandiff<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds[[targetvar]],ds[[pullvar]]),
            mean.default,na.rm=TRUE)
  b<-apply(a,1,function(x){x[2,1]-x[2,2]-(x[1,1]-x[1,2]) })
  setNames(data.frame(id=names(b),ab=b,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_doublemeandiff_old<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  idx1<-which(ds[[pullvar]]==0 & ds[[targetvar]]==1)
  idx2<-which(ds[[pullvar]]==1 & ds[[targetvar]]==1)
  idx3<-which(ds[[pullvar]]==0 & ds[[targetvar]]==0)
  idx4<-which(ds[[pullvar]]==1 & ds[[targetvar]]==0)

  ab<-(tapply(ds[[rtvar]][idx1],ds[[subjvar]][idx1],mean.default,na.rm=TRUE) -
       tapply(ds[[rtvar]][idx2],ds[[subjvar]][idx2],mean.default,na.rm=TRUE))-
      (tapply(ds[[rtvar]][idx3],ds[[subjvar]][idx3],mean.default,na.rm=TRUE) -
       tapply(ds[[rtvar]][idx4],ds[[subjvar]][idx4],mean.default,na.rm=TRUE))
  setNames(data.frame(id=names(ab),ab=ab,stringsAsFactors=F),c(subjvar,"ab"))
}

aat_doublemeandiff_older<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  group_by(ds,!!sym(subjvar)) %>%
    summarise(ab=(mean(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 1),na.rm=TRUE) -
                  mean(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 1),na.rm=TRUE)) -
                 (mean(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 0),na.rm=TRUE) -
                  mean(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 0),na.rm=TRUE)))
}

#' @export
#' @describeIn Algorithms computes a median-based double-difference score:
#' \code{(median(push_target) - median(pull_target)) - (median(push_control) - median(pull_control))}
aat_doublemediandiff<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds[[targetvar]],ds[[pullvar]]),
            median.default,na.rm=TRUE)
  b<-apply(a,1,function(x){x[2,1]-x[2,2]-(x[1,1]-x[1,2]) })
  setNames(data.frame(id=names(b),ab=b,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_doublemediandiff_old<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  idx1<-which(ds[[pullvar]]==0 & ds[[targetvar]]==1)
  idx2<-which(ds[[pullvar]]==1 & ds[[targetvar]]==1)
  idx3<-which(ds[[pullvar]]==0 & ds[[targetvar]]==0)
  idx4<-which(ds[[pullvar]]==1 & ds[[targetvar]]==0)

  ab<-(tapply(ds[[rtvar]][idx1],ds[[subjvar]][idx1],median.default,na.rm=TRUE) -
       tapply(ds[[rtvar]][idx2],ds[[subjvar]][idx2],median.default,na.rm=TRUE))-
      (tapply(ds[[rtvar]][idx3],ds[[subjvar]][idx3],median.default,na.rm=TRUE) -
       tapply(ds[[rtvar]][idx4],ds[[subjvar]][idx4],median.default,na.rm=TRUE))
  setNames(data.frame(id=names(ab),ab=ab,stringsAsFactors=F),c(subjvar,"ab"))
}

aat_doublemediandiff_older<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  group_by(ds,!!sym(subjvar)) %>%
    summarise(ab=(median(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 1),na.rm=TRUE) -
                  median(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 1),na.rm=TRUE)) -
                 (median(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 0),na.rm=TRUE) -
                  median(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 0),na.rm=TRUE)))
}

#' @export
#' @describeIn Algorithms computes D-scores for a 2-block design (see Greenwald, Nosek, and Banaji, 2003):
#' \code{((mean(push_target) - mean(pull_target)) - (mean(push_control) - mean(pull_control))) / sd(participant_reaction_times)}
aat_dscore<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds[[targetvar]],ds[[pullvar]]),
            mean.default,na.rm=TRUE)
  b<-apply(a,1,function(x){x[2,1]-x[2,2]-(x[1,1]-x[1,2]) })
  sds<-tapply(ds[[rtvar]],ds[[subjvar]],vec.sd,na.rm=TRUE)
  c<-b/sds
  setNames(data.frame(id=names(c),ab=c,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_dscore_old<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  idx1<-which(ds[[pullvar]]==0 & ds[[targetvar]]==1)
  idx2<-which(ds[[pullvar]]==1 & ds[[targetvar]]==1)
  idx3<-which(ds[[pullvar]]==0 & ds[[targetvar]]==0)
  idx4<-which(ds[[pullvar]]==1 & ds[[targetvar]]==0)

  ab<-((tapply(ds[[rtvar]][idx1],ds[[subjvar]][idx1],mean.default,na.rm=TRUE) -
        tapply(ds[[rtvar]][idx2],ds[[subjvar]][idx2],mean.default,na.rm=TRUE))-
       (tapply(ds[[rtvar]][idx3],ds[[subjvar]][idx3],mean.default,na.rm=TRUE) -
        tapply(ds[[rtvar]][idx4],ds[[subjvar]][idx4],mean.default,na.rm=TRUE)))/
        tapply(ds[[rtvar]],ds[[subjvar]],sd,na.rm=TRUE)
  setNames(data.frame(id=names(ab),ab=ab,stringsAsFactors=F),c(subjvar,"ab"))
}

aat_dscore_older<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  group_by(ds,!!sym(subjvar)) %>%
    summarise(ab=((mean(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 1),na.rm=TRUE) -
                   mean(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 1),na.rm=TRUE)) -
                  (mean(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 0),na.rm=TRUE) -
                   mean(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 0),na.rm=TRUE))) /
                   sd(!!sym(rtvar),na.rm=TRUE))
}

#' @export
#' @describeIn Algorithms computes a double-difference score usign medians,
#' and divides it by the median absolute deviation of the participant's overall reaction times:
#' \code{((median(push_target) - median(pull_target)) - (median(push_control) - median(pull_control))) / mad(participant_reaction_times)}
aat_mediandscore<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds[[targetvar]],ds[[pullvar]]),
            median.default,na.rm=TRUE)
  b<-apply(a,1,function(x){x[2,1]-x[2,2]-(x[1,1]-x[1,2]) })
  sds<-tapply(ds[[rtvar]],ds[[subjvar]],mad,na.rm=TRUE)
  c<-b/sds
  setNames(data.frame(id=names(c),ab=c,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_mediandscore_old<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  idx1<-which(ds[[pullvar]]==0 & ds[[targetvar]]==1)
  idx2<-which(ds[[pullvar]]==1 & ds[[targetvar]]==1)
  idx3<-which(ds[[pullvar]]==0 & ds[[targetvar]]==0)
  idx4<-which(ds[[pullvar]]==1 & ds[[targetvar]]==0)

  ab<-((tapply(ds[[rtvar]][idx1],ds[[subjvar]][idx1],median.default,na.rm=TRUE) -
        tapply(ds[[rtvar]][idx2],ds[[subjvar]][idx2],median.default,na.rm=TRUE))-
       (tapply(ds[[rtvar]][idx3],ds[[subjvar]][idx3],median.default,na.rm=TRUE) -
        tapply(ds[[rtvar]][idx4],ds[[subjvar]][idx4],median.default,na.rm=TRUE)))/
        tapply(ds[[rtvar]],ds[[subjvar]],mad,na.rm=TRUE)
  setNames(data.frame(id=names(ab),ab=ab,stringsAsFactors=F),c(subjvar,"ab"))
}


aat_mediandscore_older<-function(ds,subjvar,pullvar,targetvar,rtvar,...){
  group_by(ds,!!sym(subjvar)) %>%
    summarise(ab=((median(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 1),na.rm=TRUE) -
                   median(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 1),na.rm=TRUE)) -
                  (median(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 0),na.rm=TRUE) -
                   median(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 0),na.rm=TRUE))) /
                   mad(!!sym(rtvar),na.rm=TRUE))
}

#' @param blockvar name of the variable indicating block number
#' @export
#' @describeIn Algorithms computes D-scores for pairs of sequential blocks
#' and averages the resulting score (see Greenwald, Nosek, and Banaji, 2003).
#' Requires extra \code{blockvar} argument, indicating the name of the block variable.
#note: this matches sequential blocks with one another.
aat_dscore_multiblock<-function(ds,subjvar,pullvar,targetvar,rtvar,blockvar,...){
  ds$.blockset<-floor((ds[[blockvar]]-min(ds[[blockvar]]))/2)
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds$.blockset,ds[[targetvar]],ds[[pullvar]]),
            mean.default,na.rm=TRUE)
  b<-apply(a,1:2,function(x){x[2,1]-x[2,2]-(x[1,1]-x[1,2]) })
  sds<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds$.blockset),vec.sd,na.rm=TRUE)
  c<-rowMeans(b/sds)
  setNames(data.frame(id=names(c),ab=c,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_dscore_multiblock_old<-function(ds,subjvar,pullvar,targetvar,rtvar,blockvar,...){
  ds %>% mutate(.blockset = floor((!!sym(blockvar) - min(!!sym(blockvar)))/2) ) %>%
    group_by(!!sym(subjvar),.data$.blockset) %>%
    summarise(ab=((mean(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 1),na.rm=TRUE) -
                   mean(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 1),na.rm=TRUE)) -
                  (mean(subset(!!sym(rtvar),!!sym(pullvar)==0 & !!sym(targetvar) == 0),na.rm=TRUE) -
                   mean(subset(!!sym(rtvar),!!sym(pullvar)==1 & !!sym(targetvar) == 0),na.rm=TRUE))) /
                   sd(!!sym(rtvar),na.rm=TRUE)) %>%
    group_by(!!sym(subjvar)) %>% summarise(ab=mean(ab,na.rm=TRUE))
}

#' @param formula A regression formula to fit to the data to compute an AAT score
#' @param aatterm A character naming the formula term representing the approach bias.
#' Usually this is the interaction of the movement-direction and stimulus-category terms.
#' @export
#' @describeIn Algorithms \code{aat_regression} and \code{aat_standardregression} fit regression models to participants' reaction times and extract a term that serves as AAT score.
#' \code{aat_regression} extracts the raw coefficient, equivalent to a mean difference score.
#' \code{aat_standardregression} extracts the t-score of the coefficient, standardized on the basis of the variability of the participant's reaction times.
#' These algorithms can be used to regress nuisance variables out of the data before computing AAT scores.
#' When using these functions, additional arguments must be provided:
#' \itemize{
#' \item \code{formula} - a formula to fit to the data
#' \item \code{aatterm} - the term within the formula that indicates the approach bias; this is usually the interaction of the pull and target terms.
#' }
aat_regression<-function(ds,subjvar,formula,aatterm,...){
  output<-data.frame(pp=unique(ds[[subjvar]]),ab=NA,var=NA)
  for(i in seq_len(nrow(output))){
    mod<-coef(summary(lm(formula,data=ds[ds[[subjvar]]==output[i,"pp"],])))
    if(aatterm %in% rownames(mod)){
      output[i,"ab"]<- -mod[rownames(mod)==aatterm,1]
      output[i,"var"]<- mod[rownames(mod)==aatterm,2]
    }
  }
  colnames(output)[colnames(output)=="pp"]<-subjvar
  return(output)
}

#' @export
#' @describeIn Algorithms See above
aat_standardregression<-function(ds,subjvar,formula,aatterm,...){
  output<-data.frame(pp=unique(ds[[subjvar]]),ab=NA,var=NA)
  for(i in seq_len(nrow(output))){
    mod<-coef(summary(lm(formula,data=ds[ds[[subjvar]]==output[i,"pp"],])))
    if(aatterm %in% rownames(mod)){
      output[i,"ab"]<- -mod[rownames(mod)==aatterm,1]
      output[i,"var"]<- mod[rownames(mod)==aatterm,2]
    }
  }
  colnames(output)[colnames(output)=="pp"]<-subjvar
  output$ab<-output$ab/output$var
  return(output)
}

#' @export
#' @describeIn Algorithms subtracts the mean approach reaction time from the mean avoidance reaction time.
#' Using this algorithm is only sensible if the supplied data contain a single stimulus category.
aat_singlemeandiff<-function(ds,subjvar,pullvar,rtvar,...){
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds[[pullvar]]),mean.default,na.rm=T)
  b<-apply(a,1,function(x){ x[1]-x[2] })
  setNames(data.frame(id=names(b),ab=b,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_singlemeandiff_old<-function(ds,subjvar,pullvar,rtvar,...){
  idx1<-which(ds[[pullvar]]==0)
  idx2<-which(ds[[pullvar]]==1)

  ab<-(tapply(ds[[rtvar]][idx1],ds[[subjvar]][idx1],mean.default,na.rm=T) -
       tapply(ds[[rtvar]][idx2],ds[[subjvar]][idx2],mean.default,na.rm=T))
  setNames(data.frame(id=names(ab),ab=ab,stringsAsFactors=F),c(subjvar,"ab"))
}

aat_singlemeandiff_older<-function(ds,subjvar,pullvar,rtvar,...){
  group_by(ds,!!sym(subjvar))%>%
    summarise(ab=mean(subset(!!sym(rtvar),!!sym(pullvar)==1)) -
                 mean(subset(!!sym(rtvar),!!sym(pullvar)==0)))
}

#' @export
#' @describeIn Algorithms subtracts the median approach reaction time from the median avoidance reaction time.
#' Using this algorithm is only sensible if the supplied data contain a single stimulus category.
aat_singlemediandiff<-function(ds,subjvar,pullvar,rtvar,...){
  a<-tapply(ds[[rtvar]],list(ds[[subjvar]],ds[[pullvar]]),median.default,na.rm=T)
  b<-apply(a,1,function(x){ x[1]-x[2] })
  setNames(data.frame(id=names(b),ab=b,stringsAsFactors=F),
           c(subjvar,"ab"))
}

aat_singlemediandiff_old<-function(ds,subjvar,pullvar,rtvar,...){
  idx1<-which(ds[[pullvar]]==0)
  idx2<-which(ds[[pullvar]]==1)
  ab<-(tapply(ds[[rtvar]][idx1],ds[[subjvar]][idx1],median.default,na.rm=T) -
       tapply(ds[[rtvar]][idx2],ds[[subjvar]][idx2],median.default,na.rm=T))
  setNames(data.frame(id=names(ab),ab=ab,stringsAsFactors=F),c(subjvar,"ab"))
}

aat_singlemediandiff_older<-function(ds,subjvar,pullvar,rtvar,...){
  group_by(ds,!!sym(subjvar))%>%
    summarise(ab=median(subset(!!sym(rtvar),!!sym(pullvar)==1)) -
                 median(subset(!!sym(rtvar),!!sym(pullvar)==0)))
}

Try the AATtools package in your browser

Any scripts or data that you put into this service are public.

AATtools documentation built on Aug. 12, 2022, 5:05 p.m.