只是爲了說明上面的示例中的意見,讓我們
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
的幾個注意事項:
- 你說「不以下snippet ...更改
DT
中的所有列...「
答案是沒有,這對data.table
非常重要。返回的對象是新的data.table
,並且DT
中的所有列都與運行代碼之前的完全相同。
參考點之上再次,注意你的代碼(DT[ , lapply(.SD, as.factor)]
)返回一個新data.table
並不會改變DT
可言。一種方法(不正確)的方式是使用中的data.frame
s完成,它將覆蓋舊的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(26, sample(kk, nn, T)))
DT[ , LETTERS[1:2] := .(sample(100, nn, T), sample(100, nn, T))]
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 848.9310 886.6289 906.8105 896.7696 925.4353 997.0001 100
# lapplys 144.5028 145.7165 154.4077 147.5586 153.2286 253.6726 100
'DT [,colSums(.SD),. SDcols = C(A, B)]'或'DT [,lapply(.SD,sum),。SDcols = -c(A,B)]' – Khashaa
使用'by'意味着在每個'A'x'B'配對中, 'DT'中每個_other_列的值。 @ Khashaa的評論是(一些方法)如何總結所有列,除了'A'和'B',_not by group_ – MichaelChirico
@ MichaelChirico,當我改變列類型時,雖然如第一個例子中那樣,'by'表示排除我猜對吧?哪一個更快? 'colSums'或'lapply'? – KTY