【问题标题】:Group by while calculating multiple values在计算多个值时分组
【发布时间】:2021-12-28 17:57:41
【问题描述】:

我正在尝试使用在data.table 中按组计算一些统计数据的函数,如下所示:

minmax <- function(vec) {
  c(min(vec), max(vec))
}
library(data.table)
iris <- as.data.table(iris)
iris[, c('Min', 'Max') := minmax(Petal.Length), by = Species]

结果应该是Petal.Length 乘以Species 的最小值和最大值,并且具有与物种一样多的行。也就是和下面的代码结果一样:

merge(
  iris[, .(Min = min(Petal.Length)), Species],
  iris[, .(Max = max(Petal.Length)), Species],
  on = 'Species'
)

      Species Min Max
1:     setosa 1.0 1.9
2: versicolor 3.0 5.1
3:  virginica 4.5 6.9

注意:在我自己的代码中,我想一次性完成,而不是使用merge()

【问题讨论】:

标签: r group-by data.table


【解决方案1】:

这里有几件事:

  1. := 用于向现有框架添加列,因此它不会像您演示的那样进行汇总。也就是说,DT[, a := b] 应该始终具有完全相同的行数。我认为这不是您需要的。

  2. 您可以在汇总代码中进行多重赋值并取消 merge(也许这类似于您所说的“一次性”执行的代码):

    iris[, .(Min = min(Petal.Length), Max = max(Petal.Length)), by = .(Species)]
    #       Species   Min   Max
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    
  3. 但最后,你问的是如何使用你的函数来获得这个。第一次尝试可能是:

    minmax <- function(vec) c(min(vec), max(vec))
    iris[, minmax(Petal.Length), by = .(Species)]
    #       Species    V1
    #        <fctr> <num>
    # 1:     setosa   1.0
    # 2:     setosa   1.9
    # 3: versicolor   3.0
    # 4: versicolor   5.1
    # 5:  virginica   4.5
    # 6:  virginica   6.9
    
    iris[, as.list(minmax(Petal.Length)), by = .(Species)]
    #       Species    V1    V2
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    
    iris[, setNames(as.list(minmax(Petal.Length)), c("Min", "Max")), by = .(Species)]
    #       Species   Min   Max
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    
    minmax <- function(vec) c(Min = min(vec), Max = max(vec))
    iris[, as.list(minmax(Petal.Length)), by = .(Species)]
    #       Species   Min   Max
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    

    所以我们可以更改函数以返回一个列表(可选命名)。

    minmax <- function(vec) list(min(vec), max(vec))
    iris[, minmax(Petal.Length), by = .(Species)]
    #       Species    V1    V2
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    iris[, setNames(minmax(Petal.Length), c("Min", "Max")), by = .(Species)]
    #       Species   Min   Max
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    
    minmax <- function(vec) list(Min = min(vec), Max = max(vec))
    iris[, minmax(Petal.Length), by = .(Species)]
    #       Species   Min   Max
    #        <fctr> <num> <num>
    # 1:     setosa   1.0   1.9
    # 2: versicolor   3.0   5.1
    # 3:  virginica   4.5   6.9
    

【讨论】:

  • 这对我有用,谢谢!无法在 [? 中指定列名?
  • 这个答案中有几个选项允许您在返回值上设置名称,因为函数本身没有命名它们。见setNames(as.list(...))的使用,最近编辑在里面。
  • summarizingnaming 的关键是生成一个list (as.list) 并使用setNames 而没有实际的@987654332 @-assignment。
  • 是的,现在我明白了。我一直在尝试使用向量。在任何情况下,使用向量都不是一个好主意,因为它不能处理多种类型。
  • @BobJansen 只要记住j的基本属性即可;直接来自帮助文本:“只要j 返回一个list,列表的每个元素都会成为结果data.table 中的一列”干杯
猜你喜欢
  • 1970-01-01
  • 2022-11-22
  • 1970-01-01
  • 2017-09-23
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
  • 1970-01-01
  • 2021-06-11
相关资源
最近更新 更多