说我有一个像iris
这样的数据框:
> data(iris)
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
例如,我想聚合数据帧,以便获得每个Sepal.Width
的平均值Species
。在这种情况下,我会这样做:
> library(data.table)
> dd <- data.table(iris)
> dagg <- as.data.frame(dd[, list(Mean.value=mean(Sepal.Width)), by=list(ID=Species)])
> dagg
ID Mean.value
1 setosa 3.428
2 versicolor 2.770
3 virginica 2.974
但是,我现在面临的情况是这是函数的一部分,并且我针对不同的数据帧和不同的列进行了处理。
所以现在我将列名存储在变量中,所以我尝试:
> idvar <- "Species"
> valvar <- "Sepal.Width"
> dd <- data.table(iris)
> dagg <- as.data.frame(dd[, list(Mean.value=mean(iris[,valvar])), by=list(ID=iris[,idvar])])
> dagg
ID Mean.value
1 setosa 3.057333
2 versicolor 3.057333
3 virginica 3.057333
结果显然是错误的;正确执行此操作的方法是什么?谢谢!
答案 0 :(得分:3)
您可以将.SDcols
和by
包装在c()
中,以将列作为字符串传递。
library(data.table)
dd <- data.table(iris)
aggregator <- function(DT, col2avg, new.name = "avg", by = NULL) {
out <-
if (is.null(by)) {
DT[, lapply(.SD, mean), .SDcols = c(col2avg)][]
} else {
DT[, lapply(.SD, mean), .SDcols = c(col2avg), by = c(by)][]
}
setnames(out, col2avg, new.name)
out[]
}
aggregator(dd, col2avg = "Sepal.Width", by = "Species", new.name = "Mean.value")
#> Species Mean.value
#> 1: setosa 3.428
#> 2: versicolor 2.770
#> 3: virginica 2.974
(如果需要,还可以加上setnames(out, by, "ID")
)。
使用by = c(by)
而不是by = by
可以清楚地表明RHS是代表列名的字符串,因为data.table
会先查找名为"by"
的列,无论表中by
的值。
答案 1 :(得分:1)
如果您愿意考虑使用dplyr
而不是data.table
,请使用tidy evaluation。
library(dplyr)
idvar <- "Species"
valvar <- "Sepal.Width"
iris %>%
group_by(!!sym(idvar)) %>%
summarise(Mean.value = mean(!!sym(valvar)))
# A tibble: 3 x 2
Species Mean.value
<fct> <dbl>
1 setosa 3.43
2 versicolor 2.77
3 virginica 2.97