【问题标题】:generating sums of data according to values of a variable根据变量的值生成数据总和
【发布时间】:2012-10-12 10:48:26
【问题描述】:

我有类似这样的数据:

Hosp    Score   Var1    Var2    Var3
1       0       5       3       0
1       1       10      8       1
1       2       11      8       2
1       3       5       3       2
2       0       6       4       0
2       2       10      6       1
2       3       10      7       2
3       1       4       3       2
etc...

大约有 800 家医院和 4 个等级的因子得分 (0,1,2,3)。一些医院没有针对特定分数水平的观察

我想生成一个新的数据框,其中变量 Var1、Var2 和 Var3 相加。所以使用上面的数据会给

Hosp    Var1    Var2    Var3
1       32      22      5
2       26      17      3
3       4       3       2

这在 SQL 中是微不足道的(我猜它在 R 中也是如此!),但到目前为止我发现的唯一方法是使用循环,每次 Hosp 更改时都会添加一个新行,并在变量没有变化时增加变量't 改变(当然数据是在 Hosp 上排序的)。

有没有巧妙的方法来做到这一点?

【问题讨论】:

    标签: r aggregate


    【解决方案1】:

    使用aggregate()。假设您的 data.frame 被命名为“temp”,请使用:

    aggregate(list(Var1 = temp$Var1, Var2 = temp$Var2, Var3 = temp$Var3), 
              list(Hosp = temp$Hosp), sum)
    #   Hosp Var1 Var2 Var3
    # 1    1   31   22    5
    # 2    2   26   17    3
    # 3    3    4    3    2
    

    要以slick 的方式执行此操作,请使用aggregate() 的公式表示法:

    aggregate(cbind(Var1, Var2, Var3) ~ Hosp, temp, sum)
    

    但是请注意,NA 值在默认 data.frame 方法和 formula 方法中的处理方式有所不同。

    更新

    您在原始问题中提到使用 SQL。我对 SQL 没有太多经验,但也有 sqldf 包,您可以使用它执行以下操作:

    sqldf("select Hosp, 
          sum(Var1) `Var1`, sum(Var2) `Var2`, sum(Var3) `Var3` 
          from temp 
          group by Hosp")
    #   Hosp Var1 Var2 Var3
    # 1    1   31   22    5
    # 2    2   26   17    3
    # 3    3    4    3    2
    

    【讨论】:

    • @longrob,还可以查看“应用”函数系列,了解其他类型的聚合可能对此类工作有用。 “doBy”包也很有用。
    【解决方案2】:

    data.table 的内存、编码和时间效率解决方案。

    鉴于您习惯于使用SQL,您应该会发现data.table 的语法很简单,一旦您查看了data.table 的小插曲。

    # assuming your data is in DF
    library(data.table)
    DT <- data.table(DF)
    
    DT[, lapply(.SD, sum), by = hosp, .SDcols = c('Var1', 'Var2', 'Var3')]
    

    在这种情况下,您可以使用简写lapply(.SD, FUN),将.SDcols 设置为运行lapply 的变量。

    产生相同结果的更冗长但类似于SQL 的方法是

    DT[, list(Var1 = sum(Var1), Var2 =sum(Var2), Var3 = sum(Var3)), by = hosp]
    

    但你为什么要在不需要的时候编写所有这些额外的代码!

    【讨论】:

      【解决方案3】:

      solution by mrdwab 为基础,但提供更短的语法:

      aggregate(temp[3:5], temp[1], sum)
      

      这利用了数据框是一个列表的事实,因此单括号子集将生成一个包含列子集的数据框。这避免了所有list 调用。


      另一种选择:

      library(plyr)
      ddply(temp[-2], .(Hosp), colSums, na.rm = TRUE)
      

      这会将数据帧按Hosp 拆分为多个块,并以colSums(chunk, na.rm = TRUE) 的方式计算每个此类块的列总和。 [-2] 从输入中删除 Score 列,因此您不会得到总和。

      唉,正如 mrdwab 在下面的评论中正确指出的那样,上面的内容也将汇总 Hosp 列。我对这个问题的第一个解决方法如下:

      ddply(t[-2], .(Hosp), function(d){colSums(d[-1], na.rm = TRUE)})
      

      这会将Hosp 列从参数中删除到colSums,这样它就不会覆盖ddply 默认提供的该名称的原始列。总的来说,不再是一个漂亮的解决方案,也不是一个快速的解决方案。但是由于它确实有对块操作的功能,所以它非常灵活,所以我将其留作参考。

      在另一条评论中,mrdwab 提出了一个更好的解决方案:

      ddply(temp[-2], .(Hosp), numcolwise(sum))
      

      这是可行的,因为基于colwisenumcolwise 在内部调用strip_splits,而strip_splits 反过来又删除了那些用于执行拆分的列,即在这种情况下为Hosp。上一句中的所有函数都来自plyr

      【讨论】:

      • 小心,当你这样做时,plyr 替代方案也会对“Hosp”列求和!
      • 编辑你的答案以阅读以下内容,你得到了我的 +1 以迫使我做一些研究(我通常更像是一个基本的 R 人):ddply(temp[-2], .(Hosp), numcolwise(sum))
      猜你喜欢
      • 2022-08-15
      • 2017-05-05
      • 2018-12-21
      • 1970-01-01
      • 2021-08-27
      • 2020-12-09
      • 1970-01-01
      • 2019-07-29
      • 2022-01-22
      相关资源
      最近更新 更多