【问题标题】:Faster ways to calculate frequencies and cast from long to wide更快的计算频率和从长到宽投射的方法
【发布时间】:2023-09-12 09:25:01
【问题描述】:

我正在尝试获取两个变量“week”和“id”的每个级别组合的计数。我希望结果将“id”作为行,将“week”作为列,并将计数作为值。

到目前为止我尝试过的示例(尝试了很多其他方法,包括添加一个虚拟变量 = 1,然后在上面添加 fun.aggregate = sum):

library(plyr)
ddply(data, .(id), dcast, id ~ week, value_var = "id", 
        fun.aggregate = length, fill = 0, .parallel = TRUE)

但是,我一定是做错了什么,因为这个功能没有完成。有没有更好的方法来做到这一点?

输入:

id      week
1       1
1       2
1       3
1       1
2       3

输出:

  1  2  3
1 2  1  1
2 0  0  1

【问题讨论】:

    标签: r aggregate plyr reshape2


    【解决方案1】:

    您可以使用table 命令:

    table(data$id,data$week)
    
        1 2 3
      1 2 1 1
      2 0 0 1
    

    如果“id”和“week”是数据框中仅有的列,您可以简单地使用:

    table(data)
    #    week
    # id  1 2 3
    #   1 2 1 1
    #   2 0 0 1
    

    【讨论】:

    • +1 爆炸。你有一个诀窍,可以让我的解决方案看起来完全冗长、迂回和行人。
    • 如果你有很多不能简化的数据和操作,那么'data.table'包可能会对你有所帮助。
    【解决方案2】:

    您不需要ddply。来自reshape2dcast 就足够了:

    dat <- data.frame(
        id = c(rep(1, 4), 2),
        week = c(1:3, 1, 3)
    )
    
    library(reshape2)
    dcast(dat, id~week, fun.aggregate=length)
    
      id 1 2 3
    1  1 2 1 1
    2  2 0 0 1
    

    编辑:对于基本 R 解决方案(table 以外 - 由 Joshua Uhlrich 发布),请尝试 xtabs

    xtabs(~id+week, data=dat)
    
       week
    id  1 2 3
      1 2 1 1
      2 0 0 1
    

    【讨论】:

      【解决方案3】:

      ddply 花费这么长时间的原因是按组拆分不是并行运行的(仅在“拆分”上进行计算),因此如果有大量组,它会很慢(和.parallel = T ) 不会有帮助。

      使用data.table::dcastdata.table 版本 >= 1.9.2)的方法在时间和内存方面应该非常高效。在这种情况下,我们可以依赖默认参数值并简单地使用:

      library(data.table) 
      dcast(setDT(data), id ~ week)
      # Using 'week' as value column. Use 'value.var' to override
      # Aggregate function missing, defaulting to 'length'
      #    id 1 2 3
      # 1:  1 2 1 1
      # 2:  2 0 0 1
      

      或显式设置参数:

      dcast(setDT(data), id ~ week, value.var = "week", fun = length)
      #    id 1 2 3
      # 1:  1 2 1 1
      # 2:  2 0 0 1
      

      对于data.table 1.9.2 之前的替代品,请参阅编辑。

      【讨论】:

        【解决方案4】:

        tidyverse 选项可以是:

        library(dplyr)
        library(tidyr)
        
        df %>%
          count(id, week) %>%
          pivot_wider(names_from = week, values_from = n, values_fill = list(n = 0))
          #spread(week, n, fill = 0) #In older version of tidyr
        
        #     id   `1`   `2`   `3`
        #   <dbl> <dbl> <dbl> <dbl>
        #1     1     2     1     1
        #2     2     0     0     1
        

        或者使用来自janitortabyl

        janitor::tabyl(df, id, week)
        # id 1 2 3
        #  1 2 1 1
        #  2 0 0 1
        

        数据

        df <- structure(list(id = c(1L, 1L, 1L, 1L, 2L), week = c(1L, 2L, 3L, 
        1L, 3L)), class = "data.frame", row.names = c(NA, -5L))
        

        【讨论】:

          最近更新 更多