Использование lapply.SD в данных.таблица R
Мне не очень ясно, как использовать .SD и by.
Например, означает ли приведенный ниже фрагмент: "измените все столбцы в DT на фактор, кроме A и B?- В руководстве data.table также говорится: ".SD относится к подмножеству data.table для каждой группы (исключая столбцы группировки) " - так столбцы A и B исключены?
DT = DT[ ,lapply(.SD, as.factor), by=.(A,B)]
Однако я также читал, что
by означает "группировать по" в SQL, когда вы делаете агрегацию. Например, если я хотел бы суммировать (например colsum В SQL) по всем столбцам, кроме A и B, я все еще использую что-то подобное? Или в этом случае, означает ли приведенный ниже код взять сумму и сгруппировать по значениям в Столбцах A и B? (возьмем sum и group by A,B как в SQL) DT[,lapply(.SD,sum),by=.(A,B)]
Тогда как я могу сделать простой colsum над всеми столбцами, кроме A и B?
1 ответ:
Просто чтобы проиллюстрировать комментарии выше на примере, давайте возьмем
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. Возвращаемый объект является новымdata.table, и все столбцы вDTточно такие же, какими они были до запуска кода.
- вы упомянули желая изменить типы столбцов
Снова обращаясь к пункту выше, обратите внимание, что ваш код (
Это расточительно, потому что это включает в себя создание копийDT[ , lapply(.SD, as.factor)]) возвращает newdata.tableи совсем не меняетсяDT. Один (неверный ) способ сделать это, который выполняется сdata.frames в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 ссылка на семантику виньетки подробнее об этом.Вы упомянули сравнение эффективности
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
Comments