【问题标题】:How to create a pivot table in R with multiple (3+) variables如何在 R 中创建具有多个(3+)变量的数据透视表
【发布时间】:2013-09-08 11:49:23
【问题描述】:

我在使用这样的数据框创建数据透视表时遇到问题:

c1   c2          c3         c4
E   5.76         201    A la vista
E   47530.71     201    A la vista
E   82.85        201    A la vista
L   11376.55     201    A la vista
E   6683.37      203    A la vista
E   66726.52     203    A la vista
E   2.39         203    A la vista
E   79066.07     202    Montoxv_a60d
E   14715.71     202    Montoxv_a60d
E   22661.78     202    Montoxv_a60d
L   81146.25     124    Montoxv_a90d
L   471730.2     124    Montoxv_a186d
E   667812.84    124    Montoxv_a186d

我的问题是我不知道如何在 R 中创建具有四个变量的数据透视表或汇总表,考虑到行中的最终表、c1c3 的级别以及列c4 的级别。 c2 变量的值必须按行中考虑的每个级别的总和进行聚合。我想得到这样的东西:

       A la vista   Montoxv_a60d   Montoxv_a186d  Montoxv_a90d
E 201    47619.32       0               0               0  
E 203    73412.28       0               0               0 
E 202    0           116443.56          0               0      
E 124    0              0            667812.84          0 
L 201    11376.55       0               0               0
L 124    0              0            471730.2         81146.25 

【问题讨论】:

  • 也许你可以试试reshape
  • 基本解决方案是 table 或 ftable。

标签: r reshape


【解决方案1】:

您可以使用 reshape2 包中的 dcast 执行此操作:

dcast(mydata, c1 + c3 ~ c4, value.var="c2", fun.aggregate=sum)

例如:

library(reshape2)
# reproducible version of your data
mydata = read.csv(text="c1,c2,c3,c4
    E,5.76,201,A la vista
    E,47530.71,201,A la vista
    E,82.85,201,A la vista
    L,11376.55,201,A la vista
    E,6683.37,203,A la vista
    E,66726.52,203,A la vista
    E,2.39,203,A la vista
    E,79066.07,202,Montoxv_a60d
    E,14715.71,202,Montoxv_a60d
    E,22661.78,202,Montoxv_a60d
    L,81146.25,124,Montoxv_a90d
    L,471730.2,124,Montoxv_a186d
    E,667812.84,124,Montoxv_a186d", header=TRUE)
result = dcast(mydata, c1 + c3 ~ c4, value.var="c2", fun.aggregate=sum)

产生:

  c1  c3 A la vista Montoxv_a186d Montoxv_a60d Montoxv_a90d
1  E 124       0.00      667812.8          0.0         0.00
2  E 201   47619.32           0.0          0.0         0.00
3  E 202       0.00           0.0     116443.6         0.00
4  E 203   73412.28           0.0          0.0         0.00
5  L 124       0.00      471730.2          0.0     81146.25
6  L 201   11376.55           0.0          0.0         0.00

【讨论】:

  • 您也可以跳过paste 并使用c1 + c3 ~ c4 将它们保存在具有相同聚合结果的单独列中。
  • @Justin:经过反思,我确实更喜欢这个结果,尽管我不确定 OP 正在寻找哪个
  • 两者都是有用且有效的。基础R reshape,其语法对我来说是一个永远的谜,可以完成类似于我认为的粘贴方法的事情......
【解决方案2】:

请求:“c2 变量的值必须按每个级别的总和进行聚合”可以分解为一个聚合步骤,该步骤使用tapply 创建一个 3 维表对象,然后可以将其呈现为展平(使用ftable) 行有 2 维,列有 1 维:

ftable(with(mydata, tapply(c2, list(c1,c3,c4), sum) ) )

           A la vista Montoxv_a186d Montoxv_a60d Montoxv_a90d
                                                             
    E 124          NA     667812.84           NA           NA
      201    47619.32            NA           NA           NA
      202          NA            NA    116443.56           NA
      203    73412.28            NA           NA           NA
    L 124          NA     471730.20           NA     81146.25
      201    11376.55            NA           NA           NA
      202          NA            NA           NA           NA
      203          NA            NA           NA           NA

【讨论】:

    【解决方案3】:

    这里还有一些选项,两个在基础 R 中,一个使用更新的“dplyr”和“tidyr”包。

    Base R 的reshape 无法处理聚合,因此您需要借助其他函数(例如,aggregate)才能进行整形。

    reshape(
      aggregate(c2 ~ c1 + c3 + c4, mydata, sum), 
      direction = "wide", idvar = c("c1", "c3"), timevar = "c4")
    #      c1  c3 c2.A la vista c2.Montoxv_a186d c2.Montoxv_a60d c2.Montoxv_a90d
    # 1     E 201      47619.32               NA              NA              NA
    # 2     L 201      11376.55               NA              NA              NA
    # 3     E 203      73412.28               NA              NA              NA
    # 4     E 124            NA         667812.8              NA              NA
    # 5     L 124            NA         471730.2              NA        81146.25
    # 6     E 202            NA               NA        116443.6              NA
    

    如果你的聚合只涉及 sum,你也可以使用xtabs 来做聚合。由于您在公式的 RHS 上有多个值,因此您最终会得到一个多维的 array,但是可以通过使用 ftable 轻松地将其强制转换为矩形形式(正如 @BondedDust 在他的回答)。请注意,使用ftable 的输出与其他输出略有不同,因为它默认返回分组变量的所有组合,即使在其他情况下会出现完全空的行。

    ftable(xtabs(c2 ~ c1 + c3 + c4, mydata))
    #           c4 A la vista Montoxv_a186d Montoxv_a60d Montoxv_a90d
    # c1    c3                                                       
    #     E 124          0.00     667812.84         0.00         0.00
    #       201      47619.32          0.00         0.00         0.00
    #       202          0.00          0.00    116443.56         0.00
    #       203      73412.28          0.00         0.00         0.00
    #     L 124          0.00     471730.20         0.00     81146.25
    #       201      11376.55          0.00         0.00         0.00
    #       202          0.00          0.00         0.00         0.00
    #       203          0.00          0.00         0.00         0.00
    

    最后,您还可以使用“tidyr”和“dplyr”中的函数,它们提供与“reshape”和“reshape2”中的工具类似的功能,但“语法”略有不同。

    library(tidyr)
    library(dplyr)
    mydata %>%                     ## The source dataset
      group_by(c1, c3, c4) %>%     ## Grouping variables
      summarise(c2 = sum(c2)) %>%  ## aggregation of the c2 column
      ungroup() %>%                ## spread doesn't seem to like groups
      spread(c4, c2)               ## spread makes the data wide
    # Source: local data frame [6 x 6]
    # 
    #      c1  c3 A la vista Montoxv_a186d Montoxv_a60d Montoxv_a90d
    # 1     E 124         NA      667812.8           NA           NA
    # 2     E 201   47619.32            NA           NA           NA
    # 3     E 202         NA            NA     116443.6           NA
    # 4     E 203   73412.28            NA           NA           NA
    # 5     L 124         NA      471730.2           NA     81146.25
    # 6     L 201   11376.55            NA           NA           NA
    

    【讨论】:

      【解决方案4】:

      这也可以通过pivottabler 包轻松生成 - 使用单行快速旋转函数或更详细的语法:

      df <- read.csv(text="c1,c2,c3,c4
          E,5.76,201,A la vista
          E,47530.71,201,A la vista
          E,82.85,201,A la vista
          L,11376.55,201,A la vista
          E,6683.37,203,A la vista
          E,66726.52,203,A la vista
          E,2.39,203,A la vista
          E,79066.07,202,Montoxv_a60d
          E,14715.71,202,Montoxv_a60d
          E,22661.78,202,Montoxv_a60d
          L,81146.25,124,Montoxv_a90d
          L,471730.2,124,Montoxv_a186d
          E,667812.84,124,Montoxv_a186d", header=TRUE)
      
      # quick pivot syntax
      library(pivottabler)
      qhpvt(df, c("c1","c3"), "c4", "sum(c2)", totals="NONE")
      
      # verbose syntax
      library(pivottabler)
      pt <- PivotTable$new()
      pt$addData(df) 
      pt$addColumnDataGroups("c4", addTotal=FALSE)
      pt$addRowDataGroups("c1", addTotal=FALSE)
      pt$addRowDataGroups("c3", addTotal=FALSE)
      pt$defineCalculation(calculationName="calc1", summariseExpression="sum(c2)")
      pt$renderPivot()
      

      输出:

      有关pivottabler 包的更多信息,请访问: http://pivottabler.org.uk/articles/v01-introduction.html

      注意:我是包作者。

      【讨论】:

        【解决方案5】:

        使用 rpivotTable,您可以像在 Excel 中一样进行旋转。

        install.packages("rpivotTable")
        library(rpivotTable) 
        data(mtcars)
        rpivotTable(mtcars)
        

        【讨论】:

          【解决方案6】:

          使用tidyr 中的pivot_wider 函数,这可以轻松完成

          library(tidyr)
          tidyr::pivot_wider(data = df, id_cols = c(c1, c3), names_from = c4, values_from = c2, values_fn = sum)
          
          # A tibble: 6 x 6
            c1         c3 `A la vista` Montoxv_a60d Montoxv_a90d Montoxv_a186d
            <chr>   <int>        <dbl>        <dbl>        <dbl>         <dbl>
          1 "    E"   201       47619.          NA           NA            NA 
          2 "    L"   201       11377.          NA           NA            NA 
          3 "    E"   203       73412.          NA           NA            NA 
          4 "    E"   202          NA       116444.          NA            NA 
          5 "    L"   124          NA           NA        81146.       471730.
          6 "    E"   124          NA           NA           NA        667813.
          
          
          

          【讨论】:

            【解决方案7】:

            data.table 包具有类似于 reshape2 包的函数 dcast()melt() 用于此类操作。因此你可以这样做:

            require(data.table)
            
            setDT(mydata)
            dcast(mydata, c1 + c3 ~ c4,
                  value.var = "c2", fun.aggregate = sum)
            

            这也是最快的解决方案。


            来自@david-robinson 的数据。

            mydata = read.csv(text = "c1,c2,c3,c4
                E,5.76,201,A la vista
                E,47530.71,201,A la vista
                E,82.85,201,A la vista
                L,11376.55,201,A la vista
                E,6683.37,203,A la vista
                E,66726.52,203,A la vista
                E,2.39,203,A la vista
                E,79066.07,202,Montoxv_a60d
                E,14715.71,202,Montoxv_a60d
                E,22661.78,202,Montoxv_a60d
                L,81146.25,124,Montoxv_a90d
                L,471730.2,124,Montoxv_a186d
                E,667812.84,124,Montoxv_a186d", header = TRUE)
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多