我对.SD
和by
的使用不是很清楚。
例如,下面的代码段是否意味着:'将DT
中的所有列更改为除A
和B
以外的因素?'它还在data.table
手册中说:“.SD
是指每个组data.table
的子集(不包括分组列)” - 所以列A
和{{1 }} 被排除在外?
B
但是,我还读到,当你进行聚合时,DT = DT[ ,lapply(.SD, as.factor), by=.(A,B)]
就像在SQL中的'group by'一样。例如,如果我想在除by
和colsum
之外的所有列上求和(比如SQL中的A
),我还会使用类似的东西吗?或者在这种情况下,下面的代码是否意味着在B
和A
列中获取总和和值? (按照SQL中的B
取总和和分组)
A,B
那么除了DT[,lapply(.SD,sum),by=.(A,B)]
和colsum
之外,我如何对所有列进行简单的A
?
答案 0 :(得分:52)
只是用一个例子说明上面的评论,让我们来看看
set.seed(10238)
# A and B are the "id" variables within which the
# "data" variables C and D vary meaningfully
DT = data.table(A = rep(1:3, each = 5), B = rep(1:5, 3),
C = sample(15), D = sample(15))
DT
# A B C D
# 1: 1 1 14 11
# 2: 1 2 3 8
# 3: 1 3 15 1
# 4: 1 4 1 14
# 5: 1 5 5 9
# 6: 2 1 7 13
# 7: 2 2 2 12
# 8: 2 3 8 6
# 9: 2 4 9 15
# 10: 2 5 4 3
# 11: 3 1 6 5
# 12: 3 2 12 10
# 13: 3 3 10 4
# 14: 3 4 13 7
# 15: 3 5 11 2
比较以下内容:
#Sum all columns
DT[ , lapply(.SD, sum)]
# A B C D
# 1: 30 45 120 120
#Sum all columns EXCEPT A, grouping BY A
DT[ , lapply(.SD, sum), by = A]
# A B C D
# 1: 1 15 38 43
# 2: 2 15 30 49
# 3: 3 15 52 28
#Sum all columns EXCEPT A
DT[ , lapply(.SD, sum), .SDcols = !"A"]
# B C D
# 1: 45 120 120
#Sum all columns EXCEPT A, grouping BY B
DT[ , lapply(.SD, sum), by = B, .SDcols = !"A"]
# B C D
# 1: 1 27 29
# 2: 2 17 30
# 3: 3 33 11
# 4: 4 23 36
# 5: 5 20 14
一些注意事项:
DT
中的所有列..." 答案是否,这对data.table
非常重要。返回的对象是 new data.table
,DT
中的所有列都与运行代码之前完全相同。
再次参考上述观点,请注意您的代码(DT[ , lapply(.SD, as.factor)]
)会返回新 data.table
,并且根本不会更改DT
。使用data.frame
中的base
来完成此操作的一种方式(不正确的)是使用新data.table
覆盖旧data.table
你已经退回了,即DT = DT[ , lapply(.SD, as.factor)]
。
这很浪费,因为它涉及创建DT
的副本,当DT
很大时,它可以成为效率杀手。对此问题采用正确的data.table
方法是使用`:=`
按引用更新列,例如DT[ , names(DT) := lapply(.SD, as.factor)]
,这不会创建数据副本。有关详情,请参阅data.table
's reference semantics vignette。
lapply(.SD, sum)
的效率与colSums
的效率进行比较。 sum
内部优化了data.table
(您可以注意到verbose = TRUE
}中添加[]
参数的输出是正确的;为了看到这一点,让我们提高你的DT
并运行一个基准:结果:
library(data.table)
set.seed(12039)
nn = 1e7; kk = seq(100L)
DT = as.data.table(replicate(26L, sample(kk, nn, TRUE)))
DT[ , LETTERS[1:2] := .(sample(100L, nn, TRUE), sample(100L, nn, TRUE))]
library(microbenchmark)
microbenchmark(times = 100L,
colsums = colSums(DT[ , !c("A", "B"), with = FALSE]),
lapplys = DT[ , lapply(.SD, sum), .SDcols = !c("A", "B")])
# Unit: milliseconds
# expr min lq mean median uq max neval
# colsums 1624.2622 2020.9064 2028.9546 2034.3191 2049.9902 2140.8962 100
# lapplys 246.5824 250.3753 252.9603 252.1586 254.8297 266.1771 100