【问题标题】:how to add row sum and col sum at the same time by subject and then arrange subject by total如何按主题同时添加行总和和列总和,然后按总计排列主题
【发布时间】:2021-03-03 05:37:13
【问题描述】:

我有一个如下所示的数据集:

如果我想按主题和每个日期获取小计,并根据主题总数排列主题,我该怎么办?

最终输出应该如下所示(蓝色部分是我们需要添加的部分,也是总 ELA (23)

可以使用代码构建示例表:

df <- structure(list(Subject = c("Math", "Math", "Math", "Math", "ELA", 
"ELA", "ELA"), date = c(1, 7, 14, 21, 1, 7, 21), A = c(1, 2, 
0, 9, 2, 6, 0), B = c(3, 5, 5, 1, 0, 5, 0), C = c(2, 1, 0, 8, 
0, 0, 0), D = c(0, 0, 2, 8, 0, 8, 2)), row.names = c(NA, -7L), class = c("tbl_df", 
"tbl", "data.frame"))

【问题讨论】:

    标签: r


    【解决方案1】:

    使用包Janitor快速完成

    df %>% mutate(date = as.character(date)) %>%
      group_split(Subject) %>%
      map_df(., janitor::adorn_totals, fill = "All Dates", name = "Sub-Total") %>%
      adorn_totals(where = "col")
             
    
       Subject      date  A  B  C  D Total
           ELA         1  2  0  0  0     2
           ELA         7  6  5  0  8    19
           ELA        21  0  0  0  2     2
     Sub-Total All Dates  8  5  0 10    23
          Math         1  1  3  2  0     6
          Math         7  2  5  1  0     8
          Math        14  0  5  0  2     7
          Math        21  9  1  8  8    26
     Sub-Total All Dates 12 14 11 10    47
    

    如果你不将列date改成一个字符,它也会被总计

    【讨论】:

      【解决方案2】:

      这是一个基本的 R 解决方案。主要功能有

      1. byaddmargins,计算 Subject 的每组总数和行总数;
      2. 第二个循环 (lapply) 将列总计作为第一行。

      其余代码将所有内容放在一起。

      res <- by(df[-1], df[1], FUN = function(x){
        x <- as.matrix(x)
        rownames(x) <- x[, 1]
        addmargins(x[, -1], margin = 1:2) 
      })
      res <- lapply(seq_along(res), function(i){
        x <- as.data.frame(res[[i]])
        row.names(x)[row.names(x) == "Sum"] <- "All dates"
        y <- cbind.data.frame(Subject = names(res)[i], date = row.names(x), x)
        names(y)[ncol(y)] <- "Total"
        y[order(y[["Total"]], decreasing = TRUE), ]
      })
      i <- sapply(res, '[', 1, "Total")
      res <- do.call(rbind.data.frame, res[order(i, decreasing = TRUE)])
      row.names(res) <- NULL
      
      res
      #  Subject      date  A  B  C  D Total
      #1    Math All dates 12 14 11 10    47
      #2    Math        21  9  1  8  8    26
      #3    Math         7  2  5  1  0     8
      #4    Math        14  0  5  0  2     7
      #5    Math         1  1  3  2  0     6
      #6     ELA All dates  8  5  0 10    23
      #7     ELA         7  6  5  0  8    19
      #8     ELA         1  2  0  0  0     2
      #9     ELA        21  0  0  0  2     2
      

      【讨论】:

      • 排列部分需要一些调整。在主题内,按日期排序;主题顺序由所有日期的总数决定
      • @Stataq 完成,看看现在是否可以解决问题。代码改为使用addmargins
      【解决方案3】:

      这是一种 dplyr 方式:

      library(dplyr)
      
      c_order <- c('All dates', 1, 7, 14, 21)
      
      df %>%
        group_by(Subject) %>%
        summarise(across(A:D, sum)) %>%
        mutate(date = 'All dates', .after = 'Subject') %>%
        bind_rows(df %>% mutate(date = as.character(date))) %>%
        arrange(Subject, match(date, c_order)) %>%
        mutate(Total = rowSums(select(., A:D)))
      
      # Subject  date          A     B     C     D Total
      #  <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl>
      #1 ELA     All dates     8     5     0    10    23
      #2 ELA     1             2     0     0     0     2
      #3 ELA     7             6     5     0     8    19
      #4 ELA     21            0     0     0     2     2
      #5 Math    All dates    12    14    11    10    47
      #6 Math    1             1     3     2     0     6
      #7 Math    7             2     5     1     0     8
      #8 Math    14            0     5     0     2     7
      #9 Math    21            9     1     8     8    26
      

      首先为每个Subject sumA:D 添加一个值为“所有日期”的列“date”。将此绑定到原始数​​据框并根据需要的顺序排列数据并执行逐行求和。

      【讨论】:

        【解决方案4】:

        这行得通吗:

        library(dplyr)
        library(tidyr)
        
        df %>% rowwise() %>% mutate(Total = sum(c_across(A:D))) %>% 
           bind_rows(df %>% rowwise() %>% mutate(Total = sum(c_across(A:D))) %>% group_by(Subject) %>% summarise_at(vars(A:Total), sum)) %>% 
           mutate(date = replace_na(date, 'All Dates')) %>% arrange(Subject, desc(Total))
        # A tibble: 9 x 7
        # Rowwise: 
          Subject date          A     B     C     D Total
          <chr>   <chr>     <dbl> <dbl> <dbl> <dbl> <dbl>
        1 ELA     All Dates     8     5     0    10    23
        2 ELA     7             6     5     0     8    19
        3 ELA     1             2     0     0     0     2
        4 ELA     21            0     0     0     2     2
        5 Math    All Dates    12    14    11    10    47
        6 Math    21            9     1     8     8    26
        7 Math    7             2     5     1     0     8
        8 Math    14            0     5     0     2     7
        9 Math    1             1     3     2     0     6
        

        【讨论】:

        • 排列部分需要一些调整。在主题内,按日期排序;主题顺序由所有日期的总数决定。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-31
        相关资源
        最近更新 更多