首页 > 解决方案 > 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例如,我想聚合数据框,以便获得each的平均值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

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

标签: rdata.table

解决方案


您可以换行.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表外的 ' 值的列。


推荐阅读