【问题标题】:Apply function to data frames grouped by将函数应用于按以下方式分组的数据框
【发布时间】:2015-11-12 15:45:03
【问题描述】:

我想将一个函数应用于数据帧的子集,这些子集在按一些变量分组后源自初始子集。因此,我正在寻找一个与apply 或类似的等效包装器,将整个数据帧作为输入并输出一个向量。这是因为手头的函数需要来自不同地方的行和列的条目,不能简化为只使用行和列,因此形式为lapplyapply(df, 1(2),...)

让我们考虑下面的例子:

iris   <- data.table(iris)

my.function <- function(sub.data){
v <- c(NA)
    for(j in 2:dim(sub.data)[1]){
        if(sub.data[j,1, with = FALSE] > sub.data[j-1,2, with = FALSE]+2){
            v[j] <- "ok"
        } else {
            v[j] <- "not ok"    
        }
    }
    return(v)
}

执行my.function(iris) 工作正常,但假设我只想将该功能应用于具有相同物种的组。因此,在 data.table 语法中,应该如下所示:

results <- iris[,
                wrapper(.SD, my.function),
                by = Species
                ]

wrapper 是我正在寻找的环境,类型为 lapply 或类似。等效地,也可以使用包dplyr,但我不知道对应的语法是什么:我试过了

results <- iris %>%
                group_by(Species) %>%
                     summarise(results = my.function(iris))

但这似乎不会产生正确的结果,因为它仍然针对每个物种的整个数据集运行,而不是分成子集。

【问题讨论】:

  • 你想从包plyr中得到类似ddply()的东西吗?
  • summarise(results = my.function(.)) ?
  • @rawr 人们通常不会在回答时检查 cmets。请考虑将其发布为答案。
  • @rawr 是的,这就是工作。同样对于ddply,谢谢!

标签: r data.table dplyr apply


【解决方案1】:

这里似乎不需要wrapper。只需在 .SD 上运行您的函数即可满足您的需求。

library(data.table)
#your function works with a data.table
#by below will create smaller data tables on which you can directly
#run my.function on
iris[, my.function(.SD), by=Species]

输出:

       Species     V1
  1:    setosa     NA
  2:    setosa not ok
  3:    setosa not ok
  4:    setosa not ok
  5:    setosa not ok
 ---                 
146: virginica     ok
147: virginica     ok
148: virginica     ok
149: virginica     ok
150: virginica     ok

【讨论】:

    【解决方案2】:

    这里的目标是不使用包吗?

    输出向量的长度是否与 data.frame 的行数相同?如果是这样,请尝试ave,我们使用了一个测试my.function,它返回行数乘以其输入数据帧的列数:

    my.function <- function(x) prod(dim(x)) # test function
    ave(1:nrow(iris), iris$Species, FUN = function(ix) my.function(iris[ix, ]))
    ##  [1] 250 250 250 250 250 250 250 250 ...
    

    如果 my.function 返回一个长度与输入行数相同的向量,上述方法也有效。

    如果在这种情况下你只想要一个长度为 3 的向量:

    tapply(1:nrow(iris), iris$Species, function(ix) my.function(iris[ix, ]))
    ## setosa versicolor  virginica 
    ##    250        250        250 
    

    by

    c(by(iris, iris$Species, my.function))
    ## setosa versicolor  virginica 
    ##    250        250        250 
    

    sapply/split:

    sapply(split(iris, iris$Species), my.function)
    ## setosa versicolor  virginica 
    ##    250        250        250 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      • 2019-05-01
      • 2013-01-27
      • 1970-01-01
      相关资源
      最近更新 更多