Применение нескольких функций к нескольким столбцам в data.table
Я пытаюсь применить несколько функций к нескольким столбцам data.table
, Пример:
DT <- data.table("a"=1:5,
"b"=2:6,
"c"=3:7)
Допустим, я хочу получить среднее значение и медиану столбцов a
а также b
, Это работает:
stats <- DT[,.(mean_a=mean(a),
median_a=median(a),
mean_b=mean(b),
median_b=median(b))]
Но это слишком повторяется. Есть ли хороший способ добиться аналогичного результата с помощью .SDcols
а также lapply
?
2 ответа
Я обычно делаю это:
my.summary = function(x) list(mean = mean(x), median = median(x))
DT[, unlist(lapply(.SD, my.summary)), .SDcols = c('a', 'b')]
#a.mean a.median b.mean b.median
# 3 3 4 4
Другие ответы показывают, как это сделать, но никто не удосужился объяснить основной принцип. Основное правило заключается в том, что элементы списков возвращаются j
выражения образуют столбцы результирующего data.table
, любой j
выражение, которое создает список, каждый элемент которого соответствует желаемому столбцу в результате, будет работать. Имея это в виду, мы можем использовать
DT[, c(mean = lapply(.SD, mean),
median = lapply(.SD, median)),
.SDcols = c('a', 'b')]
## mean.a mean.b median.a median.b
## 1: 3 4 3 4
или же
DT[, unlist(lapply(.SD,
function(x) list(mean = mean(x),
median = median(x))),
recursive = FALSE),
.SDcols = c('a', 'b')]
## a.mean a.median b.mean b.median
## 1: 3 3 4 4
в зависимости от желаемого заказа.
Важно отметить, что мы можем использовать любой метод, который хотим получить желаемый результат, при условии, что мы упорядочим результат в виде списка, как описано выше. Например,
библиотека (matrixStats)
DT[, c(mean = as.list(colMeans(.SD)),
median = setNames(as.list(colMedians(as.matrix(.SD))), names(.SD))),
.SDcols = c('a', 'b')]
## mean.a mean.b median.a median.b
## 1: 3 4 3 4
тоже работает.
Это немного неуклюже, но делает работу с data.table
:
funcs = c('median', 'mean', 'sum')
m = DT[, lapply(.SD, function(u){
sapply(funcs, function(f) do.call(f,list(u)))
})][, t(.SD)]
colnames(m) = funcs
# median mean sum
#a 3 3 15
#b 4 4 20
#c 5 5 25
Использовать дкаст
DT$dday <- 1 # add a constant column
dt <- dcast(DT, dday~dday, fun=list(sum, mean), value.var = c('a', 'b'))
# dday a_sum_1 b_sum_1 a_mean_1 b_mean_1
# 1 15 20 3 4
Фактически, мы можем использовать dcast для реализации onehot и Feature Engineer.
Это может быть немного перестроено, но если вы пришли из dplyr summarize_at()
вы можете захотеть получить похожий структурированный результат.
Сначала определите функцию lapply_at()
что требует .SD
и вектор символов имен функций в качестве входных данных. Затем вы можете легко вычислить желаемую статистику и получить читаемый результат.
library(data.table)
iris_dt <- as.data.table(iris)
lapply_at <- function(var, funs, ...) {
results <- sapply(var, function(var) {
lapply(funs, do.call, list(var, ...))
})
names(results) <- vapply(names(var), paste, funs, sep = "_",
FUN.VALUE = character(length(funs)),
USE.NAMES = FALSE)
results
}
iris_dt[, lapply_at(.SD, c("mean", "sd"), na.rm = TRUE),
.SDcols = patterns("^Sepal"),
by = Species]
#> Species Sepal.Length_mean Sepal.Length_sd Sepal.Width_mean
#> 1: setosa 5.006 0.3524897 3.428
#> 2: versicolor 5.936 0.5161711 2.770
#> 3: virginica 6.588 0.6358796 2.974
#> Sepal.Width_sd
#> 1: 0.3790644
#> 2: 0.3137983
#> 3: 0.3224966
Создано 03.07.2019 пакетом REPEX (v0.2.0).