Сохранение комбинаций с нулевым счетчиком при объединении с 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
Спасибо большое!
Ответы
Ответ 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