using t.test within data.table on multiple columns

Viewed 677

I am trying to run a t.test() on multiple columns of data within 'j' in a data.table. I've found a way that works, but isn't very elegant, and I feel like there's probably a more concise way using .SDcols, but haven't had any luck looking through here, or the data.table vignette. If this has been asked previously I apologize and please point me in the right direction.

My data.table has essentially the following format

DT <- data.table(name = c('a', 'b', 'c', 'a', 'b', 'c'), 
                 y = c(rnorm(6, mean = 100, sd = 30)), 
                 z = c(rnorm(6, mean = 10, sd = 3)),
                 group = rep(c('One', 'Two'), 3))

When I want to run a t.test comparing the values of y in group One and group Two, it's very straightforward:

DT[,t.test(y~group)]

If I want to get an output for both y and z the following works, but is clunky and inelegant. And with my actual data, I'm trying to do this over many columns so it would be more time consuming to type out each iteration I would like to run.

DT[,.(t.test(y~group), t.test(z~group))]

In the data.table vignette, using a function over a specific subset of columns is achieved by

DT[,lapply(.SD, mean), .SDcols = c('y', 'z')]

However replacing mean with t.test yields a one sample t.test, while I'm trying to get a two sample t.test. I've tried:

DT[,lapply(.SD, t.test, formula = .SDcols ~ group, data = DT), .SDcols = c('y', 'z')]

But this gives me a comparison between y and z, not both the comparisons of y~group and z~group.

I've tried several versions of lapply with a custom function to get the output I want, but I won't make anyone read through my walls of unsuccessful code. Needless to say I have been unable to get that to work.

Question: Is there a way via lapply() or function() or a way currently unknown to me, to get t.test to run over multiple columns of data within 'j' in a data.table?

Thanks in advance for your help, Chris

1 Answers

To pull together the parts of the answer and to rearrange to put the name in the first column (if desired for nicer printing):

library(data.table)

DT <- data.table(name = c('a', 'b', 'c', 'a', 'b', 'c'), 
                 y = c(rnorm(6, mean = 100, sd = 30)), 
                 z = c(rnorm(6, mean = 10, sd = 3)),
                 group = rep(c('One', 'Two'), 3))

 result <- 
   DT[,lapply(.SD, function(x) t.test(x ~ group)), .SDcols = y:z][
   ,ttname:=names(t.test(1:5))][  # add names
   ,.(ttname,y,z)]    # put names in first column   

 result

#         ttname                       y                       z
# 1:   statistic               0.1391646               0.1295093
# 2:   parameter                3.468876                3.559917
# 3:     p.value               0.8970165               0.9039359
# 4:    conf.int     -99.61786,109.47358     -8.209637, 8.972439
# 5:    estimate       110.7286,105.8008       11.15414,10.77274
# 6:  null.value                       0                       0
# 7:      stderr                35.41031                 2.94497
# 8: alternative               two.sided               two.sided
# 9:      method Welch Two Sample t-test Welch Two Sample t-test
# 10:   data.name              x by group              x by group
Related