Использование 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?

536   1  
r

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)]) возвращает new data.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

    Ничего не найдено.