Я хочу сделать что-то подобное COUNTIFS и SUMIFS в R, используя пакет data.table.
Вот мои данные.
library(data.table)
treesData<-as.data.table(trees)
bins<-seq(63, length.out = 10, by = 3);
aggtable <- data.table(bin1 = bins[-length(bins)], bin2 = bins[-1])
Вот чего я хочу достичь: Count - это счет по высоте, если он находится в интервале и Girth.total — это сумма по обхвату.
Вы можете использовать
cond <- expression(treesData$Height %between% .(bin1, bin2 - 1))
aggtable[, c("Count", "Girth.Total") := list(
sum(eval(cond)),
sum(treesData$Girth[eval(cond)])), by = .I]
#> aggtable
# bin1 bin2 Count Girth.Total
# <num> <num> <int> <num>
#1: 63 66 3 31.2
#2: 66 69 1 11.0
#3: 69 72 3 33.7
#4: 72 75 4 53.9
#5: 75 78 6 73.3
#6: 78 81 7 104.5
#7: 81 84 4 56.3
#8: 84 87 2 26.2
#9: 87 90 1 20.6
Предложите использовать обозначение интервалов, чтобы было понятно, какие конечные точки включены, а какие исключены.
treesData[, bin := cut(Height, bins, right = FALSE)][,
.(count = .N, tot = sum(Girth)), keyby = bin]
предоставление
Key: <bin>
bin count tot
<fctr> <int> <num>
1: [63,66) 3 31.2
2: [66,69) 1 11.0
3: [69,72) 3 33.7
4: [72,75) 4 53.9
5: [75,78) 6 73.3
6: [78,81) 7 104.5
7: [81,84) 4 56.3
8: [84,87) 2 26.2
9: [87,90] 1 20.6
Входы
library(data.table)
treesData<-as.data.table(trees)
bins<-seq(63, length.out = 10, by = 3)
Немного проще, группируем на лету: treesData[, .(count = .N, tot = sum(Girth)), keyby = .(bin = cut(Height, bins, right = FALSE)) ]
Спасибо, пожалуйста, могу ли я запросить еще два улучшения: 1) два столбца count
и tot
справа от data.table aggtable
и 2) при запуске этого кода не отображаются выходные данные в консоли.
Если treeData[...][...]
— это решение выше, измените его на DT <- treeData[...][...][, cbind(aggtable, .SD)]
.
Альтернативой является использование неэкви-соединения и использование рычага .EACHI
:
treesData[aggtable,on=.(Height>=bin1, Height<bin2),.(ct = .N, Girth = sum(Girth)),.EACHI]
Выход:
Height Height ct Girth
<num> <num> <int> <num>
1: 63 66 3 31.2
2: 66 69 1 11.0
3: 69 72 3 33.7
4: 72 75 4 53.9
5: 75 78 6 73.3
6: 78 81 7 104.5
7: 81 84 4 56.3
8: 84 87 2 26.2
9: 87 90 1 20.6
Обратите внимание, что неэквивалентные соединения в data.table могут привести к путанице в отношении именования. Более полный вариант может быть:
aggtable = treesData[aggtable,on=.(Height>=bin1, Height<bin2),.(ct = .N, Girth = sum(Girth)),.EACHI]
setnames(aggtable, new=c("Bin1", "Bin2", "Count", "Girth.sum"))
Спасибо. Это то, что вы бы посоветовали, если бы я захотел сделать дальше aggtable[,Count := treesData[aggtable,on=.(Height>=bin1, Height<bin2),.(Count= .N, Girth.sum = sum(Girth)),.EACHI]$Count]; aggtable[,Girth.sum:= treesData[aggtable,on=.(Height>=bin1, Height<bin2),.(Count= .N, Girth.sum = sum(Girth)),.EACHI]$Girth.sum];
Это я делаю, чтобы 1) создать соответствующий столбец в aggtable
и 2) чтобы не отображать вывод в консоли.
Этот тип подхода является более общим и приводит к процедуре, которая имеет более высокую статистическую эффективность: использование движущихся окон (перекрывающихся ячеек).
@Мохит, на самом деле я бы не рекомендовал этого, потому что вы выполняете соединение дважды, по одному для каждой переменной. Смотрите мое обновление
Я думаю, что код можно встроить в сами квадратные скобки data.table, даже не используя eval и выражение.