R:data.table,按列名称存储在变量中汇总数据框架

时间:2018-08-28 03:47:48

标签: r data.table

说我有一个像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

结果显然是错误的;正确执行此操作的方法是什么?谢谢!

2 个答案:

答案 0 :(得分:3)

您可以将.SDcolsby包装在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