【问题标题】:How to sort a dataframe in R by one variable while grouping for others如何在为其他变量分组时按一个变量对R中的数据框进行排序
【发布时间】:2020-03-23 13:11:30
【问题描述】:

我有一个数据框:

library(tidyverse)
test_frame <- tibble(var_1 = rep(c("a", "b"), 5),
                     var_2 = c("a1", "a1", "a2", "a2", "a3", "a3", "a4", "a4", "a5", "a5"),
                     var_3 = runif(10, min = 1, max = 5))
test_frame
# A tibble: 10 x 3
   var_1 var_2 var_3
   <chr> <chr> <dbl>
 1 a     a1     4.00
 2 b     a1     4.12
 3 a     a2     2.77
 4 b     a2     1.33
 5 a     a3     3.95
 6 b     a3     3.02
 7 a     a4     2.44
 8 b     a4     2.57
 9 a     a5     1.35
10 b     a5     2.11

我希望它按 var_3 排序,但仅适用于 var_1 中具有值“a”的行,以将 var_2 中具有相同值的行保持在一起。像这样:

# A tibble: 10 x 3
   var_1 var_2 var_3
   <chr> <chr> <dbl>
 1 a     a1     4.00
 2 b     a1     4.12
 5 a     a3     3.95
 6 b     a3     3.02
 3 a     a2     2.77
 4 b     a2     1.33
 7 a     a4     2.44
 8 b     a4     2.57
 9 a     a5     1.35
10 b     a5     2.11

我尝试了不同的“group_by”和“arrange”组合,但没有成功。我错过了什么?

【问题讨论】:

    标签: r sorting dplyr grouping


    【解决方案1】:

    使用基数 R,按 'var_3' 值加倍 'var_2' 排序。

    with(test_frame, test_frame[order(-rep(var_3[!duplicated(var_2)], each=2)), ])
    # # A tibble: 10 x 3
    #    var_1 var_2 var_3
    #    <chr> <chr> <dbl>
    #  1 a     a4     4.79
    #  2 b     a4     1.33
    #  3 a     a2     3.24
    #  4 b     a2     4.62
    #  5 a     a5     3.06
    #  6 b     a5     2.56
    #  7 a     a3     1.55
    #  8 b     a3     4.96
    #  9 a     a1     1.47
    # 10 b     a1     2.90
    

    数据

    test_frame <- structure(list(var_1 = c("a", "b", "a", "b", "a", "b", "a", "b", 
    "a", "b"), var_2 = c("a1", "a1", "a2", "a2", "a3", "a3", "a4", 
    "a4", "a5", "a5"), var_3 = c(1.46994944661856, 2.89998832624406, 
    3.24133098497987, 4.61612554918975, 1.55484067089856, 4.95556691568345, 
    4.78667293023318, 1.32975023239851, 3.05684713739902, 2.56081386841834
    )), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"
    ))
    

    【讨论】:

      【解决方案2】:

      一个dplyr 选项可能是:

      test_frame %>%
       mutate(ranking = dense_rank(desc((var_1 == "a") * var_3))) %>%
       group_by(var_2) %>%
       mutate(ranking = min(ranking)) %>%
       arrange(ranking) %>%
       select(-ranking)
      
         var_1 var_2 var_3
         <chr> <chr> <dbl>
       1 a     a4     4.46
       2 b     a4     2.68
       3 a     a5     2.80
       4 b     a5     2.65
       5 a     a1     1.91
       6 b     a1     2.99
       7 a     a3     1.22
       8 b     a3     1.93
       9 a     a2     1.10
      10 b     a2     4.92
      

      或者:

      test_frame %>%
       filter(var_1 == "a") %>%
       mutate(ranking = dense_rank(desc(var_3))) %>%
       bind_rows(test_frame %>%
                  filter(var_1 == "b")) %>%
       group_by(var_2) %>%
       mutate(ranking = min(ranking, na.rm = TRUE)) %>%
       arrange(ranking) %>%
       select(-ranking)
      

      【讨论】:

        【解决方案3】:

        一种解决方案是pivot_wider,这样您就对一个完整的变量进行排序,然后排序,然后pivot_longer 回到原来的形状。

        test_frame %>%
         pivot_wider( names_from = var_1, values_from = var_3) %>%
         arrange( -a) %>%
         pivot_longer(cols=c(a,b), names_to="var_1", values_to = "var_3")
        
        # A tibble: 10 x 3
           var_2 var_1 var_3
           <chr> <chr> <dbl>
         1 a1    a      4.21
         2 a1    b      1.82
         3 a5    a      3.71
         4 a5    b      1.25
         5 a3    a      2.76
         6 a3    b      2.58
         7 a2    a      2.60
         8 a2    b      4.32
         9 a4    a      1.12
        10 a4    b      1.54
        

        【讨论】:

          【解决方案4】:

          无需对数据框中的列进行分组、添加和删除 - 只需很好地使用 dplyr::arrange() 方法。我认为这可以满足您的需求:

          as.data.frame(test_frame) %>% arrange(var_3, var_1, var_2)
          

          这给了你这个:

              var_1 var_2    var_3
          1      b    a4 1.866265
          2      a    a4 2.703378
          3      b    a5 2.931703
          4      a    a1 2.935217
          5      a    a2 3.019241
          6      b    a1 3.029589
          7      b    a3 3.657182
          8      a    a3 4.392643
          9      b    a2 4.415388
          10     a    a5 4.498499
          

          唯一的问题是 var_2 排序为 'b',然后是 'a' - 不是 'a',然后是 'b',就像你想要的那样。可能有几种方法可以解决这个问题(您可以在 arrange() 函数中使用 desc(...) ......但我在让它工作时遇到了一些麻烦。最后,您实际上可以分离出 arrange() 函数,它一种按特定顺序对每一列进行排序的行为。这是我为您提供的最终解决方案:

          as.data.frame(test_frame) %>% arrange(var_3) %>% arrange(var_1) %>% arrange(var_2)
          
             var_1 var_2    var_3
          1      a    a1 2.935217
          2      b    a1 3.029589
          3      a    a2 3.019241
          4      b    a2 4.415388
          5      a    a3 4.392643
          6      b    a3 3.657182
          7      a    a4 2.703378
          8      b    a4 1.866265
          9      a    a5 4.498499
          10     b    a5 2.931703
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-16
            • 2019-08-18
            • 2016-07-02
            • 2021-12-09
            • 2020-05-24
            • 2021-01-01
            • 1970-01-01
            • 2022-07-07
            相关资源
            最近更新 更多