2016-09-09 3 views
2

Я хочу создать несколько переменных, которые агрегируют различные подмножества набора данных. Для примера, иллюстрирующего, что у вас есть следующие данные:Как создать несколько новых столбцов с javascript.table в разных подмножествах

DT = data.table(Group1 = c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4), 
       Group2 = c(1,1,1,2,2,1,1,2,2,2,1,1,1,1,2,1,1,2,2,2), 
        Var1 = c(1,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0)) 

Я хочу найти несколько средних значений переменной Var1. Я хочу знать:

  • mean(Var1) сгруппирован по Group1
  • mean(Var1) только для тех, кто с Group2 == 1, сгруппированным по Group1
  • mean(Var1) только для тех, кто с Group2 == 2, сгруппированным по Group1

Или, в data.table parlance,

DT[, mean(Var1), by=Group1] 
DT[Group2==1, mean(Var1), by=Group1] 
DT[Group2==2, mean(Var1), by=Group1] 

Очевидно, что вычисление любого из них очень просто. Но я не могу найти хороший способ рассчитать все три из них, так как они используют разные подмножества в i. Решение, которое я использовал до сих пор, генерирует их индивидуально, а затем объединяет их в единую таблицу.

DT_all <- DT[, .(avgVar1_all = mean(Var1)), by = Group1] 
DT_1 <- DT[Group2 == 1, .(avgVar1_1 = mean(Var1)), by = Group1] 
DT_2 <- DT[Group2 == 2, .(avgVar1_2 = mean(Var1)), by = Group1] 
group_info <- merge(DT_all, DT_1, by = "Group1") 
group_info <- merge(group_info, DT_2, by = "Group1") 

group_info 
# Group1 avgVar1_all avgVar1_1 avgVar1_2 
# 1:  1   0.4 0.6666667 0.0000000 
# 2:  2   0.6 1.0000000 0.3333333 
# 3:  3   0.2 0.2500000 0.0000000 
# 4:  4   0.0 0.0000000 0.0000000 

Есть ли более элегантный метод, который я мог бы использовать?

ответ

5

Просто делать это все в одной операции группировки с использованием .SD:

DT[, .(
     all = mean(Var1), 
     grp1 = .SD[Group2==1, mean(Var1)], 
     grp2 = .SD[Group2==2, mean(Var1)] 
    ), 
    by = Group1, 
    .SDcols=c("Group2","Var1") 
    ] 

# Group1 all  grp1  grp2 
#1:  1 0.4 0.6666667 0.0000000 
#2:  2 0.6 1.0000000 0.3333333 
#3:  3 0.2 0.2500000 0.0000000 
#4:  4 0.0 0.0000000 0.0000000 
+0

Это делает трюк, хотя не Подменю .sd в целом одобряется, для исполнения? Или это просто взятие подмножества столбцов из .SD? –

+1

@ConnorJ - Я далек от авторитета по этому вопросу, но я думаю, что подмножество '.SD' было оптимизировано очень сильно, поскольку это было проблемой. Счастлив, что Арун или Мэтт, если я ошибаюсь, похлопал себя по голове. – thelatemail

+0

@ConnorJ - теперь, когда я просматриваю некоторые детали, возможно, вы правы, и это не идеально - https://github.com/Rdatatable/data.table/issues/735 – thelatemail

3

Вы можете использовать reshape2::dcast:

reshape2::dcast(DT, Group1 ~ Group2, fun=mean, margins="Group2") 


    Group1   1   2 (all) 
1  1 0.6666667 0.0000000 0.4 
2  2 1.0000000 0.3333333 0.6 
3  3 0.2500000 0.0000000 0.2 
4  4 0.0000000 0.0000000 0.0 

@thelatmail отметил в комментарии ниже, что этот подход не очень хорошо масштабируется. В конце концов, margins should be available в data.table's dcast, что, вероятно, будет более эффективным.

Безобразная обходной путь:

DT[, c(
    dcast(.SD, Group1 ~ Group2, fun=mean), 
    all = .(dcast(.SD, Group1 ~ ., fun=mean)$.) 
)] 


    Group1   1   2 all 
1:  1 0.6666667 0.0000000 0.4 
2:  2 1.0000000 0.3333333 0.6 
3:  3 0.2500000 0.0000000 0.2 
4:  4 0.0000000 0.0000000 0.0 
+1

Очень аккуратный код, но он, похоже, задыхается от действительно больших данных. Я тестировал его на 10-мегапиксельных записях, и он съел почти все 16 ГБ моей памяти, прежде чем я его убил. – thelatemail

+0

Приятно знать, @thelatemail, спасибо. Полагаем, что в этом случае мы с нетерпением ожидаем реализации data.table. – Frank

+1

Да, мой реальный набор данных составляет около 3 млн. Строк, поэтому я буду держать 'dcast' в data.table, чтобы это произошло. Благодаря! –