2017-02-10 3 views
2

Я использую функцию smean.cl.normal из пакета Hmisc, которая возвращает вектор с тремя значениями: средний и нижний и верхний CI. Когда я использую его на data.table с двумя группами, я получаю 2 столбца и 6 строк. Есть ли способ получить результат с двумя строками, соответствующими двум группам и отдельными столбцами для каждого из выходов функции, то есть среднего и CI?data.table: lapply функция с многоколоночным выходом

require(Hmisc) 
require(data.table) 

dt = data.table(x = rnorm(100), 
       gr = rep(c('A', 'B'), each = 50)) 

dt[, lapply(.SD, smean.cl.normal), by = gr, .SDcols = "x"] 

Выход:

gr   x 
1: A -0.07916335 
2: A -0.33656667 
3: A 0.17823998 
4: B -0.02745333 
5: B -0.32950607 
6: B 0.27459941 

Нужный выход:

gr  Mean   Lower   Upper 
1: A -0.07916335 -0.33656667 0.17823998 
2: B -0.02745333 -0.32950607 0.27459941 
+0

Возможно, существует лучший способ, но следующие работы: 'dt2 <- dcast (dt [, lapply (.SD, smean.cl.normal), by = gr], gr ~ rowid (gr)); setnames (dt2, 2: 4, c ('Mean', 'Lower', 'Upper')) ' – Jaap

+0

Спасибо. Да, я тоже делал это с dcast, просто я думал, что в 'data.table' есть что-то, чего я не хватает. – mattek

+1

обратитесь к http://stackoverflow.com/questions/27494813/data-table-computing-several-column-at-once –

ответ

5

j аргумент в DT[i,j,by] ожидает, что список, так что используйте as.list:

dt[, 
    Reduce(c, lapply(.SD, function(x) as.list(smean.cl.normal(x)))) 
, by = gr, .SDcols = "x"] 

# gr  Mean  Lower  Upper 
# 1: A 0.1032966 -0.1899466 0.3965398 
# 2: B -0.1437617 -0.4261330 0.1386096 

c(L1, L2, L3), как списки объединены, поэтому Reduce(c, List_o_Lists) делает трюк в случае, если ваш .SDcols содержит больше, чем просто x. Думаю, do.call(c, List_o_Lists) также должен работать.


Комментарии

Это довольно неэффективно по нескольким причинам. Включите verbose=TRUE, чтобы увидеть, что data.table не любит получать именованные списки в j:

Результат J именованный список. Очень неэффективно создавать одни и те же имена снова и снова для каждой группы. Когда j = список (...), все имена обнаруживаются, удаляются и возвращаются после завершения группировки для эффективности. Например, использование j = transform() предотвращает это ускорение (рассмотрим изменение на: =). В будущем это сообщение может быть обновлено до предупреждения.

Кроме того, вы отсутствуете в оптимизированных по групповой версии версиях mean и других функциях, которые могут быть использованы для построения вашего результата. Тем не менее, это не может быть большой проблемой для вашего прецедента.


Когда вы подаете это только колонки одного значения, просто:

dt[, as.list(smean.cl.normal(x)), by = gr] 

суффиксов.

+1

Удивительно, спасибо миллион за подробный ответ! – mattek

Смежные вопросы