Сохранение комбинаций с нулевым счетчиком при объединении с data.table - программирование

Сохранение комбинаций с нулевым счетчиком при объединении с data.table

Предположим, у меня есть следующий data.table:

dt <- data.table(id = c(rep(1, 5), rep(2, 4)),
                 sex = c(rep("H", 5), rep("F", 4)), 
                 fruit = c("apple", "tomato", "apple", "apple", "orange", "apple", "apple", "tomato", "tomato"),
                 key = "id")

   id sex  fruit
1:  1   H  apple
2:  1   H tomato
3:  1   H  apple
4:  1   H  apple
5:  1   H orange
6:  2   F  apple
7:  2   F  apple
8:  2   F tomato
9:  2   F tomato

Каждая строка представляет тот факт, что кто-то (идентифицированный им id и sex) съел fruit. Я хочу подсчитать количество раз, когда каждый fruit был съеден sex. Я могу сделать это с помощью:

dt[ , .N, by = c("fruit", "sex")]

Что дает:

    fruit sex N
1:  apple   H 3
2: tomato   H 1
3: orange   H 1
4:  apple   F 2
5: tomato   F 2

Проблема заключается в том, что я делаю это так, что теряю счет orange для sex == "F", потому что этот счет равен 0. Есть ли способ сделать эту агрегацию без потери комбинаций нулевого значения?

Чтобы быть совершенно ясным, желаемый результат был бы следующим:

   fruit sex N
1:  apple   H 3
2: tomato   H 1
3: orange   H 1
4:  apple   F 2
5: tomato   F 2
6: orange   F 0

Спасибо большое!

4b9b3361

Ответ 1

Похоже, что самый простой подход заключается в том, чтобы явно предоставлять все комбо категории в таблице data.table, переданной в i=, устанавливая by=.EACHI для итерации по ним:

setkey(dt,sex,fruit)[CJ(unique(sex), unique(fruit)), .N, by=.EACHI]
#    sex  fruit N
# 1:   F  apple 2
# 2:   F orange 0
# 3:   F tomato 2
# 4:   H  apple 3
# 5:   H orange 1
# 6:   H tomato 1

Ответ 2

Один из способов - изменить sex или id на коэффициент (id здесь избыточно?)

dt[, sex := factor(sex)]
dt[, list(sex=levels(sex), N=c(table(sex))), by="fruit"]
#     fruit sex N
# 1:  apple   F 2
# 2:  apple   H 3
# 3: tomato   F 2
# 4: tomato   H 1
# 5: orange   F 0
# 6: orange   H 1

Или вы можете изменить fruit на коэффициент и группу на sex:

dt[, fruit := factor(fruit)]
dt[, list(fruit = levels(fruit), N=c(table(fruit))),by=sex]
#    sex  fruit N
# 1:   H  apple 3
# 2:   H orange 1
# 3:   H tomato 1
# 4:   F  apple 2
# 5:   F orange 0
# 6:   F tomato 2

Edit:

Но я подозреваю, что ваша таблица данных огромна, тогда в зависимости от table может быть не очень хорошая идея. В этом случае использование CJ из вашего более раннего вопроса может быть способом. То есть сначала сделайте агрегацию, а затем выполните соединение.

out <- setkey(dt, sex, fruit)[, .N, 
             by="sex,fruit"][CJ(c("H","F"), 
             c("apple","tomato","orange")), 
             allow.cartesian=TRUE][is.na(N), N := 0L]
#    sex  fruit N
# 1:   F  apple 2
# 2:   F orange 0
# 3:   F tomato 2
# 4:   H  apple 3
# 5:   H orange 1
# 6:   H tomato 1