tests/testthat/test_bootES.R

## Daniel Gerlanc and Kris Kirby (2010-2012)
## Input and regression tests for the bootES function

get_gender <- function() {
  gender <- read.csv(system.file("example.csv", package="bootES"),
                      strip.white=TRUE, header=TRUE)
  gender$GenderByCond <- paste(gender$Gender, gender$Condition, sep = "-")
  gender
}

test_that("bootES handles invalid 'R' values", {
  r_check_message = paste0(
    "R must be of 'type' integer or 'type' real with no ",
    "fractional or decimal parts")

  ## Pass an 'R' with a fractional portion
  res <- try(bootES(data.frame(scores=1), R=0.5), silent=TRUE)
  expect_true(grepl(r_check_message, res))

  ## Pass an 'R' with string
  res <- try(bootES(data.frame(scores=1), R="5"), silent=TRUE)
  expect_true(grepl(r_check_message, res))

  ## Pass an 'R' with a negative value
  res <- try(bootES(data.frame(scores=1), R=-1), silent=TRUE)
  expect_true(grepl("R must be of length 1 and >= 0", res))
})

test_that("bootES handles invalid inputs", {
  gender = get_gender()

  g1 = c(11, 12, 13, 14, 15)
  g2 = c(26, 27, 28, 29)
  g3 = c(17, 18, 19, 20, 21, 22, 23)
  
  grpLabels = rep(c("A", "B", "C"), times=c(length(g1), length(g2), length(g3)))
  threeGps  = data.frame(grpLabels, scores=c(g1, g2, g3))
  threeGpsVec = c(g1, g2, g3)
  lambdas   = c(A=-1, B=2, C=-1)
    
  ## Pass a non-data.frame object as 'data'
  res = try(bootES("foo"), silent=TRUE)
  expect_true(grepl("'data' must be a data.frame or numeric vector.", res))

  ## Pass an invalid 'group' to 'contrast'
  res = try(bootES(gender, data.col="Meas3",
    group.col="Condition", contrast = c(Fake = -50, C = 50),
    scale.weights=TRUE), silent=TRUE)
  expect_true(grepl("'Fake' is/are not valid groups.", res[1]))
  
  ## Pass a data.frame to 'data' with no records
  expect_error(bootES(data.frame()))
  
  ## Pass an 'R' of length greater than 1
  expect_error(bootES(data.frame(scores=1), R=c(2, 1)))

  ## Use a 'data.col' not in 'data'
  expect_error(bootES(threeGps, R=250, data.col="foo"))

  ## Use a 'glass.control' value that is not a valid group
  res <- try(bootES(data.frame(scores=1), glass.control="foo"), silent=TRUE)
  expect_true(grepl("'glass.control' is not", res))
  
  ## Assert that using a block.col and glass.control together generates
  ## an error
  res <- try(bootES(gender, 
                    data.col="Meas1",
                    block.col="Gender", group.col="Condition",
                    glass.control="female",
                    contrast=c(A=1, B=-0.5, C=-0.5)), 
             silent=TRUE)
  expect_true(grepl("Cannot use 'block.col'", res))
  
  ## Use 'glass.control' and 'block.col' together w/out a data column
  ## and w/out contrasts
  res <- try(bootES(gender, block.col="Gender", grp.col="Condition"), 
             silent=TRUE)
  
  ## Use 'glass.control' and 'block.col' together w/out a data column
  res <- try(bootES(gender, block.col="Gender", group.col="Condition",
                    contrast=c(A=1, B=-0.5, C=-0.5)), 
             silent=TRUE)
  
  ## Assert that user cannot pass '...' arguments that are not valid 'boot'
  ## arguments.
  res <- try(bootES(gender, R=10, data.col="Meas1", block.col="Condition", 
                    slop.levels=letters[1:3]), 
             silent=TRUE)
  expect_true(grepl('invalid argument.*slop\\.levels', res[1], ignore.case=TRUE))

})

test_that("univariate statistics produce known results with bootES", {

  gender = get_gender()
  g1 = c(11, 12, 13, 14, 15)
  g2 = c(26, 27, 28, 29)
  g3 = c(17, 18, 19, 20, 21, 22, 23)
  
  grpLabels = rep(c("A", "B", "C"), times=c(length(g1), length(g2), length(g3)))
  threeGps  = data.frame(grpLabels, scores=c(g1, g2, g3))
  threeGpsVec = c(g1, g2, g3)
  lambdas   = c(A=-1, B=2, C=-1)
  
  ## Test: 'meanBoot' through 'bootES'
  set.seed(1)
  truth    = mean(threeGps$scores)
  mean.res = bootES(threeGps, R=250, data.col="scores",
    effect.type="unstandardized")
  mean.res.vec = bootES(threeGpsVec, effect.type="unstandardized")
  expect_equal(truth, mean.res$t0)
  expect_equal(truth, mean.res.vec$t0)

  ## Test: 'rMeanBoot' through 'bootES'
  set.seed(1)
  truth     = bootES:::rMean(threeGps$scores)
  rMean.res = bootES(threeGps, R=300, data.col="scores", effect.type="r")
  expect_equal(truth, rMean.res$t0)

  ## Test: 'dMeanBoot' through 'bootES'
  set.seed(1)
  truth     = bootES:::dMean(threeGps$scores)
  rMean.res = bootES(threeGps, R=300, data.col="scores",
    effect.type="cohens.d")
  expect_equal(truth, rMean.res$t0)

  ## Test: 'dMeanBoot' and Cohen's Sigma d through 'bootES'
  set.seed(1)
  truth     = bootES:::dSigmaMeanBoot(threeGps$scores,
    1:length(threeGps$scores))
  rMean.res = bootES(threeGps, R=300, data.col="scores",
    effect.type="cohens.d.sigma")
  expect_equal(truth, rMean.res$t0)
  
  ## Test: 'hMeanBoot' and Hedge's g through 'bootES'
  set.seed(1)
  truth     = bootES:::hMean(threeGps$scores)
  rMean.res = bootES(threeGps, R=300, data.col="scores",
    effect.type="hedges.g")
  expect_equal(truth, rMean.res$t0)
  
  ## Test: 'akpRobustD' through 'bootES'
  dat = read.csv(system.file("robust_d_test.csv", package="bootES"))
  truth     = 0.190912
  set.seed(1)
  akp.res = bootES(dat, R=250, data.col="diff", effect.type="akp.robust.d")
  expect_equal(truth, akp.res$t0, tolerance=1e-4)
  
  set.seed(1)
  akp.res.1 = bootES(dat[["diff"]], R=250, effect.type="akp.robust.d")
  expect_equal(truth, akp.res.1$t0, tolerance=1e-4)
})

test_that("multivariate statistics produce known results with bootES", {

  gender = get_gender()
  g1        = c(11, 12, 13, 14, 15)
  g2        = c(26, 27, 28, 29)
  grpLabels = rep(c("A", "B"), times=c(length(g1), length(g2)))
  twoGpsA   = data.frame(x=c(g1, g2), team=grpLabels)
  twoGpsErr = data.frame(x=c(g1, g2), team=rep("A", length(c(g1, g2))))
  lambdas   = c(A=1, B=-1)
  
  ## Integration test of stat='contrast' and effect.type='unstandardized'
  set.seed(1)
  truth     = mean(g1) - mean(g2)
  unstdDiff.res = bootES(twoGpsA, R=250, data.col="x", group.col="team",
    effect.type="unstandardized", contrast=lambdas)
  expect_equal(truth, unstdDiff.res$t0)
   
  ## Integration test of stat='contrast' and effect.type='unstandardized' where
  ## there is only one group. This should cause an error.
  unstdDiff.err = try(bootES(twoGpsErr, R=250, data.col="x", group.col="team",
    effect.type="unstandardized"), silent=TRUE)    

  ## Integration test of stat='contrast' and effect.type='cohens.d.sigma'
  set.seed(1)
  test = bootES(gender, R=250, data.col="Meas1", group.col="Gender",
    effect.type="cohens.d.sigma", contrast=c(female=1, male=-1))
  expect_equal(-0.50104, test$t0, tolerance=1e-2)

  set.seed(1)
  test = bootES(gender, R=250, data.col="Meas1", group.col="Gender",
    effect.type="cohens.d.sigma", contrast=c(female=-1, male=+1))
  expect_equal(0.50104, test$t0, tolerance=1e-2)

  ## Integration test of stat='contrast' and effect.type='cohens.d.sigma'
  ## w/ glass control
  set.seed(1)
  test = bootES(gender, R=250, data.col="Meas1", group.col="Gender",
    effect.type="cohens.d.sigma", contrast=c('female', 'male'),
    glass.control='female')
  expect_equal(0.588, test$t0, tolerance=1e-2)

  ## Integration test of stat='contrast' and effect.type='cohens.d'
  ## w/ glass control
  set.seed(1)
  test = bootES(gender, R=250, data.col="Meas1", group.col="Gender",
    effect.type="cohens.d", contrast=c('female', 'male'),
    glass.control='female')
  expect_equal(0.557, test$t0, tolerance=1e-2)
  
  ## Integration test of stat='cor'
  set.seed(1)
  g1        = c(11, 12, 13, 14, 15)
  g2        = c(26, 27, 28, 29)
  twoGps    = data.frame(g1=g1)
  twoGps$g2 = rep(g2, length.out=nrow(twoGps))
  truth     = with(twoGps, cor(g1, g2))
  cor.res   = suppressWarnings(bootES(twoGps, R=10, effect.type="r"))
  expect_equal(truth, cor.res$t0)
})

test_that("hedges.g produces known results ", {
  gender = get_gender()

  set.seed(1)
  truth = 0.5096
  test  = bootES(gender, R=250, data.col = "Meas1", group.col = "Gender", 
                 contrast = c("female","male"), 
                 effect.type="hedges.g", glass.control="female")
  expect_equal(truth, test$t0, tolerance=1e-3)
})

test_that("'contrast' functionality produces known results", {
  gender = get_gender()

  ## Assert: Calculated value matches known value for an unstandardized
  ## contrast
  set.seed(1)
  truth = -522.43
  test  = bootES(gender, R=250, data.col="Meas3", group.col="Condition",
    contrast = c(A = -40, B = -10, C = 50), scale.weights=FALSE)
  expect_equal(truth, test$t0, tolerance=1e-2)

  ## Assert: Calculated value matches known value for an unstandardized
  ## contrast with weights scaled
  set.seed(1)
  truth.contrast.scaled = -10.4486
  test  = bootES(gender, R=250, data.col="Meas3", group.col="Condition",
    contrast = c(A = -40, B = -10, C = 50), scale.weights=TRUE)
  expect_equal(truth.contrast.scaled, test$t0, tolerance=1e-4)

  ## Assert: Calculated value matches known value for an unstandardized
  ## contrast with weights scaled and a group left out
  set.seed(1)
  truth.contrast.omit = -3.0535
  test  = bootES(gender, R=250, data.col="Meas3", group.col="Condition",
    contrast = c(A = -1, C = 1))  
  expect_equal(truth.contrast.omit, test$t0, tolerance=1e-4)

  ## Assert: Default weights of -1 and 1 are used when not passed in
  test.dflt  = bootES(gender, R=250, data.col="Meas3", group.col="Condition",
    contrast = c('A', 'C'))
  expect_equal(truth.contrast.omit, test.dflt$t0, tolerance=1e-4)

  ## Assert: Scales user-specified weights
  set.seed(1)
  truth = -0.45488
  test = bootES(gender, R=250, data.col = "Meas1", group.col = "Gender",
    contrast=c(female = 3, male = -3), effect.type = "hedges.g")
  expect_equal(truth, test$t0, tolerance=1e-3)
  
  gender$GenderByCond = paste(gender$Gender, gender$Condition, sep = "-")
  set.seed(1)
  truth = 46.71499
  test <- bootES(gender, data.col="Meas1", group.col="GenderByCond", 
                 contrast = c("female-A" = -40, "male-A" = -40, 
                              "female-B" = -10, "male-B" = -10, 
                              "female-C" = 50, "male-C" = 50))
  expect_equal(truth, test$t0, tolerance=1e-3)

  ## Assert: Test the blocking column w/ contrasts that must be scaled
  set.seed(1)
  truth = 46.71499
  test = bootES(gender, R=250, data.col="Meas1",
    block.col="GenderByCond", group.col="Condition",
    contrast=c(A=-40, B=-10, C=50))
  expect_equal(truth, test$t0, tolerance=1e-3)
  
  ## Assert: Test the blocking column w/ contrasts that don't need to
  ## be scaled
  set.seed(1)
  truth = 36.783
  test <- bootES(gender, R=250, data.col="Meas1", group.col="Gender",
                 contrast=c("female"=-1, "male"=1), block.col="Condition")
  expect_equal(truth, test$t0, tolerance=1e-3)
  cond_means <- with(gender, tapply(Meas1, GenderByCond, mean))
  
  ## Assert: Test that means are unweighted
  set.seed(1005)
  # means <- with(gender, tapply(Meas1, Condition, mean))
  # truth <- with(gender, mean(tapply(Meas1, Condition, mean)))
  truth <- 266.944 # unweighted mean 
  test <- bootES(gender, R=250, data.col="Meas1", block.col="Condition")
  expect_equal(truth, test$t0, tolerance=1e-3)
#   wt_mean <- local({
#     means <- with(gender, tapply(Meas1, GenderByCond, mean))
#     counts <- with(gender, tapply(Meas1, GenderByCond, length))
#     sum(means * counts / nrow(gender))
#   })

})

test_that("apk.robust.d produces known results", {
  gender = get_gender()
  truth = 0.5487
  test.1 = bootES(gender, R=250, data.col="Meas1", group.col="Gender",
                  contrast=c(male=1, female=-1), 
                  effect.type="akp.robust.d")
  expect_equal(test.1$t0, truth, tolerance=1e-3)
})

test_that("'cor.dirr' functionality produces known results", {
  ## Unit test of stat='cor.diff'
  ## Note that R=300 set so runs quickly but does not generate warnings
  ## when calculating CIs
  gender = get_gender()
  set.seed(1)

  iris = get(data("iris"))
  cols = c("Species", "Sepal.Length", "Petal.Length")
  iris_sv = iris[iris$Species %in% c("setosa", "versicolor"), cols]
  iris_ls = split(iris_sv, iris_sv$Species)
  setosa = iris_ls[["setosa"]]
  versicolor = iris_ls[["versicolor"]]
  truth = (cor(setosa$Sepal.Length, setosa$Petal.Length) -
    cor(versicolor$Sepal.Length, versicolor$Petal.Length))

  cor.diff.res = bootES(iris_sv, R=300, group.col="Species", effect.type="r")
  expect_equal(truth, cor.diff.res$t0)
})

test_that("slope functionality produces known results", {
  ## Regression test for when effect.type='slope'
  gender = get_gender()
  set.seed(1)
  truth <- -0.1244
  test  <- bootES(gender, R=200, data.col="Meas3", group.col="Condition",
                  slope.levels=c(A=30, B=60, C=120))
  expect_equal(truth, test$t0, tolerance=1e-2)
  
  test  <- bootES(gender, R=200, data.col="Meas3", slope.levels="Dosage")
  expect_equal(truth, test$t0, tolerance=1e-2)
                  
})

test_that("'effect.type' functionality produces known results", {
  g1 = c(11, 12, 13, 14, 15)
  g2 = c(26, 27, 28, 29)
  g3 = c(17, 18, 19, 20, 21, 22, 23)
  
  grpLabels = rep(c("A", "B", "C"), times=c(length(g1), length(g2), length(g3)))
  threeGps  = data.frame(grpLabels, scores=c(g1, g2, g3))
  threeGpsVec = c(g1, g2, g3)
  lambdas   = c(A=-1, B=2, C=-1)
  
  ## Test: 'meanBoot' through 'bootES'
  set.seed(1)
  truth    = mean(threeGps$scores)
  mean.res = bootES(threeGps, R=250, data.col="scores",
    effect.type="unstandardized")
  mean.res.vec = bootES(threeGpsVec, effect.type="unstandardized")
  expect_equal(truth, mean.res$t0)
  expect_equal(truth, mean.res.vec$t0)

  ci.types = eval(formals(bootES)$ci.type)
  ci.types = ci.types[!ci.types %in% "stud"]
  for (ci.type in ci.types) {
    set.seed(1)
    if (ci.type == "stud") {
      . <- bootES(threeGps, R=250, data.col="scores",
                  effect.type="unstandardized", ci.type=ci.type,
                  var.t0=1, var.t=1)
    } else {
      . <- bootES(threeGps, R=250, data.col="scores",
                  effect.type="unstandardized", ci.type=ci.type)
    }
  }
})

test_that("blocking functionality produces known results", {
  ## testgroup: Calls calcUnstandardizedMean through the bootES interface
  
  ## Assert that blocking and grouping work exactly the same when the 
  ## contrasts are specified at the block or group level

  gender = get_gender()

  set.seed(1)
  test.1a = bootES(gender, R=999, data.col="Meas1", group.col="Gender", 
                   contrast=c(female=-1, male=1), block.col="GenderByCond")
  
  set.seed(1)
  test.1b = bootES(gender, R=999, 
                   data.col = "Meas1", group.col = "GenderByCond", 
                   contrast = c("female-A"=-1, "female-B"=-1, "female-C"=-1, 
                                "male-A"=1, "male-B"=1, "male-C"=1))
  
  expect_equal(summary(test.1a), summary(test.1b))
  
  ## testgroup: Calls calcCohensD through the bootES interface
  set.seed(1)
  test.2a = bootES(gender, R=999, data.col="Meas1", group.col="Gender", 
                   contrast=c(female=-1, male=1), block.col="GenderByCond",
                   effect.type="cohens.d")
  
  set.seed(1)
  test.2b = bootES(gender, R=999, effect.type="cohens.d",
                   data.col = "Meas1", group.col = "GenderByCond", 
                   contrast = c("female-A"=-1, "female-B"=-1, "female-C"=-1, 
                                "male-A"=1, "male-B"=1, "male-C"=1))
  expect_equal(summary(test.1a), summary(test.1b))
  
  ## test: Assert that bootES automatically crosses them
  set.seed(1)
  test.3 = bootES(gender, R=999, data.col="Meas1", group.col="Gender", 
                  contrast=c(female=-1, male=1), block.col="Condition")
  expect_equal(summary(test.3), summary(test.1a))
  
})

Try the bootES package in your browser

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

bootES documentation built on April 11, 2023, 5:57 p.m.