Выполнить t-тест с использованием агрегатной функции в R

#r #aggregate

#r #агрегировать

Вопрос:

У меня возникают трудности с использованием непарного t-теста и агрегатной функции.

Пример

 dd<-data.frame(names=c("1st","1st","1st","1st","2nd","2nd","2nd","2nd"),a=c(11,12,13,14,2.1,2.2,2.3,2.4),b=c(3.1,3.2,3.3,3.4,3.1,3.2,3.3,3.4))
dd
#  Compare all the values in the "a" column that match with "1st" against the values in the "b" column that match "1st".  
#  Then, do the same thing with those matching "2nd"

t.test(c(11,12,13,14),c(3.1,3.2,3.3,3.4))$p.value
t.test(c(3.1,3.2,3.3,3.4),c(3.1,3.2,3.3,3.4))$p.value

#  Also need to replace any errors from t.test that have too low variance with NA
#  An example of the type of error I might run into would be if the "b" column was replaced with c(3,3,3,3,3,3,3,3).  
  

Для парных данных я нашел обходной путь.

 #  Create Paired data.
data_paired<-dd[,3]-dd[,2]

#  Create new t-test so that it doesn't crash upon the first instance of an error.  
my_t.test<-function(x){
    A<-try(t.test(x), silent=TRUE)
    if (is(A, "try-error")) return(NA) else return(A$p.value)
}

#  Use aggregate with new t-test.  
aggregate(data_paired, by=list(dd$name),FUN=my_t.test)
  

Этот агрегат работает с одним столбцом входных данных. Однако я не могу заставить ее функционировать, когда мне нужно, чтобы в функцию входило несколько столбцов.

Пример:

 my_t.test2<-function(x,y){
    A<-try(t.test(x,y,paired=FALSE), silent=TRUE)
    if (is(A, "try-error")) return(NA) else return(A$p.value)
}

aggregate(dd[,c(2,3)],by=list(dd$name),function(x,y) my_t.test2(dd[,3],dd[,2]))
  

Я думал, что агрегатная функция отправит только строки, соответствующие значению в списке, в функцию my_t.test2, а затем перейдет к следующему элементу списка. Однако полученные результаты указывают на то, что он выполняет t-тест для всех значений в столбце, как показано ниже. И затем поместите каждое из этих значений в результаты.

 t.test(dd[,3],dd[,2])$p.value
  

Чего мне не хватает? Это проблемы с исходным my_test.2, проблема с тем, как структурировать агрегатную функцию, или что-то еще. То, как я ее применил, похоже, не агрегирует.

Это результаты, которые я хочу.

 t.test(c(11,12,13,14),c(3.1,3.2,3.3,3.4))$p.value
t.test(c(3.1,3.2,3.3,3.4),c(3.1,3.2,3.3,3.4))$p.value
  

Обратите внимание, что это игрушечный пример, и фактический набор данных будет содержать более 100 000 записей, которые необходимо сгруппировать по значению в столбце имен. Следовательно, почему мне нужна агрегатная функция.

Спасибо за помощь.

Комментарии:

1. Вы говорите, что хотите сопоставить A-first с B-first, но t.test(c(11,12,13,14),c(2.1,2.2,2.3,2.4))$p.value это проверка A-first с A-second, верно? Это опечатка?

2. Да, это была опечатка. Исправил это.

Ответ №1:

aggregate это неправильная функция для использования здесь, потому что функция summary работает только с одним столбцом за раз. Невозможно получить оба a и b значения одновременно с помощью этого метода.

Другой способ, которым вы могли бы подойти к проблеме, — разделить данные, а затем применить t-тест к каждому подмножеству. Вот одна реализация

 sapply(
    split(dd[-1], dd$names), 
    function(x) t.test(x[["a"]], x[["b"]])$p.value
)
  

Здесь я разделяю dd на список подмножеств для каждого значения names . Я использую dd[-1] для удаления столбца «имена» из подмножеств, чтобы у меня был просто data.frame с двумя столбцами. Один для a и один для b .

Затем для каждого подмножества в списке я выполняю a, t.test используя столбцы a и b . Затем я извлекаю p-значение. sapply Оболочка с вычислением этого p-значения для каждого подмножества и rill вернула именованный вектор p-значений, где имена записей соответствуют уровням dd$names

          1st          2nd 
6.727462e-04 3.436403e-05 
  

Если вы хотите выполнить парный t-тест таким образом, вы могли бы сделать

 sapply(
    split(dd[-1], dd$names), 
    function(x) t.test(x[["a"]] - x[["b"]])$p.value
)
  

Комментарии:

1. Спасибо, пока это работает. Я немного незнаком с созданием объектов списка в R. Возможно, вы знаете, насколько сильно пострадает память для очень большого объекта списка по сравнению с фреймом данных?

Ответ №2:

Как сказал @MrFlick, agregate это неправильная функция для этого. Вот несколько альтернатив подходу sapply с использованием пакетов dplyr или data.table .

 require(dplyr)
summarize(group_by(dd, names), t.test(a,b)$p.value)

require(data.table)
data.table(dd)[, t.test(a,b)$p.value, by=names]