doomlab/MOTE

Use S3 methods for effect size functions

crsh opened this issue · 1 comments

crsh commented

Hi Erin,

building on our other discussion, here some thoughts on how to handle different output objects. I would suggest to define S3 methods to do this to avoid "having to write it 10 times". Currently, you suggest to do the following for every effect:

##run my analysis
aov_saved = summary(aov(mpg~cyl, data = mtcars))
##process through MOTE
eta_saved = eta.anova(aov_saved[[1]][["Df"]][1], aov_saved[[1]][["Df"]][2], aov_saved[[1]][["F value"]][1], a = .05)

I would suggest the following:

# Define S3 generic
eta_anova <- function(x, ...) {
  UseMethod("eta_anova", x)
}

# Define default method for users who want to pass statistics (e.g., from publications)
eta_anova.default <- function (x, dfm, dfe, a = .05) {
  eta <- (dfm * x) / (dfm * x + dfe)
  ncpboth <- conf.limits.ncf(x, df.1 = dfm, df.2 = dfe, conf.level = (1 - a))
  elow <- ncpboth$Lower.Limit / (ncpboth$Lower.Limit + dfm + dfe + 1)
  ehigh <- ncpboth$Upper.Limit / (ncpboth$Upper.Limit + dfm + dfe + 1)
  p <- pf(x, dfm, dfe, lower.tail = F)
  
  output <- data.frame(es = eta,
                       es_ll = elow,
                       es_ul = ehigh,
                       Fvalue = x,
                       dfm = dfm,
                       dfe = dfe)
  attr(output, "model") <- c(F = x, dfm = dfm, dfe = dfe)
  class(output) <- c("mote_anova", class(output))
  return(output)
}

# Define methods for analysis objects
eta_anova.aov <- function(x, ...) {
  x_summary <- summary(x)
  eta_anova(x_summary, ...)
}

eta_anova.summary.aov <- function(x, a = .05) {
  x_df <- x[[1]]
  
  output <- data.frame()
  for(i in 1:(nrow(x_df) - 1)) {
    output <- rbind(
      output,
      eta_anova(x_df[["F value"]][i], x_df[["Df"]][i], x_df[["Df"]][nrow(x_df)], a = a)
    )
  }
  output <- cbind(effects = rownames(x_df)[1:(nrow(x_df) - 1)], output)
  attr(output, "model") <- x
  class(output) <- c("mote_anova", class(output))
  output
}

# Run my analysis
aov_saved = aov(mpg~cyl * disp, data = mtcars)
aov_summary = summary(aov_saved)

# Process efficiently through MOTE
eta_anova(aov_summary[[1]][["F value"]][1], aov_summary[[1]][["Df"]][1], aov_summary[[1]][["Df"]][4], a = .05)
eta_anova(aov_saved)
eta_anova(aov_summary)

Adding the input object to the output facilitates interoperability with papaja.

Does that make sense? If so feel free to use this (untested) code (a contributor note would be appreciated).

@crsh - yes! Thank you for the working example - I've already thought about how to apply that to t-tests. I will play around with these ideas and see what I can do. Will definitely add a contributor note once I get my readme and manual in order.