在data.table R中使用lapply .SD

KTY*_*KTY 29 r data.table

我对使用.SD和不太清楚by.

例如,做下面的代码片段意思是:"改变所有的列DT到的因素,除了AB?" 它还在data.table手册中说:" .SDdata.table每个组的子集(不包括分组列)" - 所以列AB排除?

DT = DT[ ,lapply(.SD, as.factor), by=.(A,B)]
Run Code Online (Sandbox Code Playgroud)

但是,我也读过,by当你进行聚合时,这意味着在SQL中使用'group by'.例如,如果我想colsum在除了所有列之外总结(比如在SQL中)A并且B我仍然使用类似的东西吗?或者在这种情况下,下面的代码是否意味着在列AB?中取总和和值组?(A,B在SQL中使用sum和group by )

DT[,lapply(.SD,sum),by=.(A,B)]
Run Code Online (Sandbox Code Playgroud)

然后我如何做colsum除了A和之外的所有列的简单B

Mic*_*ico 56

只是用一个例子来说明上面的评论,让我们来看看

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
Run Code Online (Sandbox Code Playgroud)

比较以下内容:

#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
Run Code Online (Sandbox Code Playgroud)

几点说明:

  • 你说"做下面的片段......改变......中的所有列DT"

答案是否定的,这非常重要data.table.返回的对象是一个 对象data.table,并且所有列DT都与运行代码之前完全一样.

  • 您提到想要更改列类型

再次参考上面的要点,请注意您的code(DT[ , lapply(.SD, as.factor)])返回一个新的, data.table并且根本不会更改DT.使用s in 完成此操作的一种(不正确的)方法是使用您返回的新内容覆盖旧内容,即.data.framebasedata.tabledata.tableDT = DT[ , lapply(.SD, as.factor)]

这是浪费,因为它涉及创建副本,DT当副本DT很大时,副本可以成为效率杀手.data.table解决此问题的正确方法是使用`:=`,例如,通过引用更新列DT[ , names(DT) := lapply(.SD, as.factor)],这不会创建数据的副本.有关详细信息,请参阅data.table参考语义晕影.

  • 你提到的比较效率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
Run Code Online (Sandbox Code Playgroud)

  • 带有`set`的`for`循环是转换大量列的另一个选项,在本回答的底部提到并由Arun和Matt建议/认可:http://stackoverflow.com/a/16846530/1191259 (4认同)