【问题标题】:Calculating subtotals in R在 R 中计算小计
【发布时间】:2010-11-05 08:32:41
【问题描述】:

我在R中有一个90万行11列的数据框,列名和类型如下:

column name: date / mcode / mname / ycode / yname / yissue  / bsent   / breturn / tsent   / treturn / csales
type:        Date / Char  / Char  / Char  / Char  / Numeric / Numeric / Numeric / Numeric / Numeric / Numeric

我想计算小计。例如,我想计算 yname 每次更改时的总和,并将小计添加到所有数值变量中。有 160 个不同的 yname,所以结果表应该告诉我每个 yname 的小计。我还没有对数据进行排序,但这不是问题,因为我可以按照我想要的任何方式对数据进行排序。以下是我数据中的一个 sn-p:

             date     mcode mname            ycode    yname   yissue bsent breturn tsent treturn csales
417572 2010-07-28     45740 ENDPOINT A        5772    XMAG  20100800     7       0     7       0      0
417573 2010-07-31     45740 ENDPOINT A        5772    XMAG  20100800     0       0     0       0      1
417574 2010-08-04     45740 ENDPOINT A        5772    XMAG  20100800     0       0     0       0      1
417575 2010-08-14     45740 ENDPOINT A        5772    XMAG  20100800     0       0     0       0      1
417576 2010-08-26     45740 ENDPOINT A        5772    XMAG  20100800     0       4     0       0      0
417577 2010-07-28     45741 ENDPOINT L        5772    XMAG  20100800     2       0     2       0      0
417578 2010-08-04     45741 ENDPOINT L        5772    XMAG  20100800     2       0     2       0      0
417579 2010-08-26     45741 ENDPOINT L        5772    XMAG  20100800     0       4     0       0      0
417580 2010-07-28     46390 ENDPOINT R        5772    XMAG  20100800     3       0     3       0      1
417581 2010-07-29     46390 ENDPOINT R        5772    XMAG  20100800     0       0     0       0      2
417582 2010-08-01     46390 ENDPOINT R        5779    YMAG  20100800     3       0     3       0      0
417583 2010-08-11     46390 ENDPOINT R        5779    YMAG  20100800     0       0     0       0      1
417584 2010-08-20     46390 ENDPOINT R        5779    YMAG  20100800     0       0     0       0      1
417585 2010-08-24     46390 ENDPOINT R        5779    YMAG  20100800     2       0     2       0      1
417586 2010-08-26     46390 ENDPOINT R        5779    YMAG  20100800     0       2     0       2      0
417587 2010-07-28     46411 ENDPOINT D        5779    YMAG  20100800     6       0     6       0      0
417588 2010-08-08     46411 ENDPOINT D        5779    YMAG  20100800     0       0     0       0      1
417589 2010-08-11     46411 ENDPOINT D        5779    YMAG  20100800     0       0     0       0      1
417590 2010-08-26     46411 ENDPOINT D        5779    YMAG  20100800     0       4     0       4      0

我应该在这里使用什么功能?也许像 SQL group by 这样的东西?

【问题讨论】:

  • 如果您向我们提供数据的 sn-p 或您真正想要的更多详细信息,这会容易得多。当您自己不提供示例时,您要求我们提供示例具有一定程度的讽刺意味!不过说真的,大多数 R 大师很可能不会使用 Excel,而且很可能很长时间没有使用 Excel,所以当你说“像 Excel 一样做”时,不要以为我们知道你的意思。 yname 是否已排序?因为那将是 R 中的一项聚合任务(即,您需要 yname 定义的组的数字总和)。
  • @Gavin Simpson:我已根据您的评论更新了我的问题。

标签: r subtotal


【解决方案1】:

好的。假设您的数据位于名为 foo 的数据框中:

> head(foo)
             date mcode      mname ycode yname   yissue bsent breturn tsent
417572 2010/07/28 45740 ENDPOINT A  5772  XMAG 20100800     7       0     7
417573 2010/07/31 45740 ENDPOINT A  5772  XMAG 20100800     0       0     0
417574 2010/08/04 45740 ENDPOINT A  5772  XMAG 20100800     0       0     0
417575 2010/08/14 45740 ENDPOINT A  5772  XMAG 20100800     0       0     0
417576 2010/08/26 45740 ENDPOINT A  5772  XMAG 20100800     0       4     0
417577 2010/07/28 45741 ENDPOINT L  5772  XMAG 20100800     2       0     2
       treturn csales
417572       0      0
417573       0      1
417574       0      1
417575       0      1
417576       0      0
417577       0      0

然后这将对数据中的数字列进行聚合:

> aggregate(cbind(bsent, breturn, tsent, treturn, csales) ~ yname, data = foo, 
+           FUN = sum)
  yname bsent breturn tsent treturn csales
1  XMAG    14       8    14       0      6
2  YMAG    11       6    11       6      5

那是使用 Q 中包含的数据的 sn-p。我使用了 aggregate() 的公式接口,在这种情况下更好一些,因为你不需要所有 foo$ 位您希望聚合的变量名称。如果您的完整数据集中缺少数据 (NA),则需要添加一个额外的参数 na.rm = TRUE,该参数将传递给 sum(),如下所示:

> aggregate(cbind(bsent, breturn, tsent, treturn, csales) ~ yname, data = foo, 
+           FUN = sum, na.rm = TRUE)

【讨论】:

    【解决方案2】:

    或者plyr 库,它很容易扩展到其他数据类:

    > library(plyr)
    > result.2 <- ddply(df$a, .(df$b), sum)
    > result.2
      df.b V1
    1 down 30
    2   up 25
    

    【讨论】:

      【解决方案3】:

      您也可以使用xtabstapply

      xtabs(cbind(bsent, breturn, tsent, treturn, csales) ~ yname, data)
      
      tapply(data$bsent, data$yname, sum)
      

      【讨论】:

        【解决方案4】:

        如果您的数据很大并且速度很重要,我建议使用 R 函数 rowsum,它要快得多。我应用了答案中建议的 3 种方法(f1 = 聚合,f2 = ddply,f3 = tapply),将其与 f4 = rowsum 进行比较,这就是我发现的:

           test replications elapsed relative
        4 f4()          100   0.033     1.00
        3 f3()          100   0.046     1.39
        1 f1()          100   0.165     5.00
        2 f2()          100   0.605    18.33
        

        如果有人想更详细地探索,我在下面添加了我的代码。

        library(plyr);
        library(rbenchmark);
        
        val  = rnorm(50);
        name = rep(letters[1:5], each = 10);
        data = data.frame(val, name);
        
        f1 = function(){aggregate(data$val, by=list(data$name), FUN=sum)}
        f2 = function(){ddply(data, .(name), summarise, sum = sum(val))}
        f3 = function(){tapply(data$val, data$name, sum)}
        f4 = function(){rowsum(x = data$val, group = data$name)}
        
        benchmark(f1(), f2(), f3(), f4(),
                  columns=c("test", "replications", "elapsed", "relative"),
                  order="relative", replications=100)
        

        【讨论】:

          【解决方案5】:

          当我试图找到类似问题的答案时,Google 并不是很有帮助。我想我会在下面使用library(janitor) 包与split()purrr::map_df() 分享我的解决方案。

          我的用例是运行一个脚本,该脚本会从许多不同的人那里获取 CC 费用以供一个人审查。

          
          library(janitor)
          library(purrr)
          library(dplyr)
          
          mtcars %>% 
            split(.[,"cyl"]) %>% ## splits each change in cyl into a list of dataframes 
            map_df(., janitor::adorn_totals)
          
             mpg cyl   disp   hp  drat     wt   qsec vs am gear carb
            22.8   4  108.0   93  3.85  2.320  18.61  1  1    4    1
            24.4   4  146.7   62  3.69  3.190  20.00  1  0    4    2
            22.8   4  140.8   95  3.92  3.150  22.90  1  0    4    2
            32.4   4   78.7   66  4.08  2.200  19.47  1  1    4    1
            30.4   4   75.7   52  4.93  1.615  18.52  1  1    4    2
            33.9   4   71.1   65  4.22  1.835  19.90  1  1    4    1
            21.5   4  120.1   97  3.70  2.465  20.01  1  0    3    1
            27.3   4   79.0   66  4.08  1.935  18.90  1  1    4    1
              26   4  120.3   91  4.43  2.140  16.70  0  1    5    2
            30.4   4   95.1  113  3.77  1.513  16.90  1  1    5    2
            21.4   4  121.0  109  4.11  2.780  18.60  1  1    4    2
           Total  44 1156.5  909 44.78 25.143 210.51 10  8   45   17
              21   6  160.0  110  3.90  2.620  16.46  0  1    4    4
              21   6  160.0  110  3.90  2.875  17.02  0  1    4    4
            21.4   6  258.0  110  3.08  3.215  19.44  1  0    3    1
            18.1   6  225.0  105  2.76  3.460  20.22  1  0    3    1
            19.2   6  167.6  123  3.92  3.440  18.30  1  0    4    4
            17.8   6  167.6  123  3.92  3.440  18.90  1  0    4    4
            19.7   6  145.0  175  3.62  2.770  15.50  0  1    5    6
           Total  42 1283.2  856 25.10 21.820 125.84  4  3   27   24
            18.7   8  360.0  175  3.15  3.440  17.02  0  0    3    2
            14.3   8  360.0  245  3.21  3.570  15.84  0  0    3    4
            16.4   8  275.8  180  3.07  4.070  17.40  0  0    3    3
            17.3   8  275.8  180  3.07  3.730  17.60  0  0    3    3
            15.2   8  275.8  180  3.07  3.780  18.00  0  0    3    3
            10.4   8  472.0  205  2.93  5.250  17.98  0  0    3    4
            10.4   8  460.0  215  3.00  5.424  17.82  0  0    3    4
            14.7   8  440.0  230  3.23  5.345  17.42  0  0    3    4
            15.5   8  318.0  150  2.76  3.520  16.87  0  0    3    2
            15.2   8  304.0  150  3.15  3.435  17.30  0  0    3    2
            13.3   8  350.0  245  3.73  3.840  15.41  0  0    3    4
            19.2   8  400.0  175  3.08  3.845  17.05  0  0    3    2
            15.8   8  351.0  264  4.22  3.170  14.50  0  1    5    4
              15   8  301.0  335  3.54  3.570  14.60  0  1    5    8
           Total 112 4943.4 2929 45.21 55.989 234.81  0  2   46   49
          
          
          # if you're sending the output to be reviewed by a person, add a row! 
          
          mtcars %>% 
            split(.[,"cyl"]) %>% 
            map_df(., ~janitor::adorn_totals(.x) %>% 
                     dplyr::add_row()) %>% 
            write.csv(., "demo.csv")
          
          

          【讨论】:

            【解决方案6】:

            您可以使用aggregate

            比如说你有

            val = rnorm(50)
            name = rep(letters[1:5], each=10)
            data <- data.frame(val, name)
            

            那你就可以了

            aggregate(data$val, by=list(data$name), FUN=sum)
            

            【讨论】:

              【解决方案7】:

              有一个名为 sqldf 的 R 包,可让您在 R data.frames 上使用 SQL 命令。 除了就像你已经说过的那样, GROUP BY 会很好。您可以轻松地将数据存储在本地 MySQL 数据库中并使用包 RMySQL 连接到 R(您也可以使用大多数其他 DBMS,但 MySQL 是最容易设置的)。

              据我判断 plyr 也是一个很棒的软件包。但是从您提出问题并将您的问题与 GROUP BY 进行比较的方式来看,我猜您对 SQL 有所了解,因此使用它可能对您来说更容易。有一些舒适的功能,比如 dbReadTable,此外,如果您的数据变得更大,您可以只选择数据的子部分,仅使用您真正需要的内容运行您的分析。

              【讨论】:

                猜你喜欢
                • 2017-02-06
                • 1970-01-01
                • 2018-05-11
                • 1970-01-01
                • 2023-02-23
                • 1970-01-01
                • 2023-03-26
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多