【问题标题】:How to order a data frame by one descending and one ascending column?如何按一降一升列对数据框进行排序?
【发布时间】:2011-12-09 05:56:52
【问题描述】:

我有一个数据框,看起来像这样:

    P1  P2  P3  T1  T2  T3  I1  I2
1   2   3   5   52  43  61  6   "b"
2   6   4   3   72  NA  59  1   "a"
3   1   5   6   55  48  60  6   "f"
4   2   4   4   65  64  58  2   "b"

我想按I1降序排序,I1中具有相同值的行按I2升序排序,按1 3 4 2的顺序获取行。但是order 函数似乎只接受一个decreasing 参数,然后是TRUEFALSE 一次用于所有排序向量。如何正确排序?

【问题讨论】:

    标签: r sorting dataframe


    【解决方案1】:

    一般来说,xtfrm() 是获取数值向量的通用函数 类似于给定的输入向量。然后可以通过减少排序来完成 使用 xtfrm() 的否定值进行排序。 (这正是例如 dplyr 的desc() 已实现。)

    例如,有问题的数据:

    df <- read.table(text = "
    P1  P2  P3  T1  T2  T3  I1  I2
    2   3   5   52  43  61  6   b
    6   4   3   72  NA  59  1   a
    1   5   6   55  48  60  6   f
    2   4   4   65  64  58  2   b
    ", header = TRUE)
    
    df[order(-xtfrm(df$I1), df$I2), ]
    #>   P1 P2 P3 T1 T2 T3 I1 I2
    #> 1  2  3  5 52 43 61  6  b
    #> 3  1  5  6 55 48 60  6  f
    #> 4  2  4  4 65 64 58  2  b
    #> 2  6  4  3 72 NA 59  1  a
    

    这种方法可以推广到一个基本的 R 函数来排序 给定列的数据帧,也接受向量值decreasing 争论。从my answerthis recent question:

    sortdf <- function(x, by = colnames(x), decreasing = FALSE) {
      x[do.call(order, Map(sortproxy, x[by], decreasing)), , drop = FALSE]
    }
    
    sortproxy <- function(x, decreasing = FALSE) {
      as.integer((-1)^as.logical(decreasing)) * xtfrm(x)
    }
    

    使用当前的示例数据,我们(当然)得到:

    sortdf(df, by = c("I1", "I2"), decreasing = c(TRUE, FALSE))
    #>   P1 P2 P3 T1 T2 T3 I1 I2
    #> 1  2  3  5 52 43 61  6  b
    #> 3  1  5  6 55 48 60  6  f
    #> 4  2  4  4 65 64 58  2  b
    #> 2  6  4  3 72 NA 59  1  a
    

    【讨论】:

      【解决方案2】:

      减少数据框列

      df<- df[order(df$Differece, decreasing = TRUE),]
      
      df<- df[order(df$Differece, decreasing = FALSE),]
      

      【讨论】:

        【解决方案3】:

        您可以使用令人惊叹的软件包 dplyr 有一个函数叫做安排。 考虑到您选择的层次结构,您只需设置数据框和要排序的列。默认是升序。但是如果你想要降序,你可以使用命令 desc。

        rum

        图书馆(dplyr)
        安排(朗姆酒,desc(I1),I2)

        【讨论】:

        • 请显示您的命令的输出以验证正确性。此外,您的答案依赖于未提及的附加包中的功能。请添加相关的library() 电话。谢谢。
        【解决方案4】:

        简单无等级:

        rum[order(rum$I1, -rum$I2, decreasing = TRUE), ]
        

        【讨论】:

          【解决方案5】:
              library(dplyr)
              library(tidyr)
              #supposing you want to arrange column 'c' in descending order and 'd' in ascending order. name of data frame is df
              ## first doing descending
              df<-arrange(df,desc(c))
              ## then the ascending order of col 'd;
              df <-arrange(df,d)
          

          【讨论】:

            【解决方案6】:

            默认排序是稳定的,所以我们排序两次:先按次键,然后按主键

            rum1 <- rum[order(rum$I2, decreasing = FALSE),]
            rum2 <- rum1[order(rum1$I1, decreasing = TRUE),]
            

            【讨论】:

              【解决方案7】:
              rum[order(rum$T1, -rum$T2 ), ]
              

              【讨论】:

              • 用解释澄清答案
              • 这并不总是有效。如果 T2 是日期向量,它将给出错误:-.Date(rum$T2) 中的错误:一元 - 未为 Date 对象定义。这不适用于所提供的具体示例,但作为一般建议,很高兴知道。
              【解决方案8】:

              令 df 为具有 2 个字段 A 和 B 的数据框

              案例 1:如果您的字段 A 和 B 是数字

              df[order(df[,1],df[,2]),] - sorts fields A and B in ascending order
              df[order(df[,1],-df[,2]),] - sorts fields A in ascending and B in descending order
              优先考虑 A。

              案例 2:如果字段 A 或 B 不是数字,则说明因子或字符

              在我们的例子中,如果 B 是字符并且我们希望以相反的顺序排序
              df[order(df[,1],-as.numeric(as.factor(df[,2]))),] -&gt; this sorts field A(numerical) in ascending and field B(character) in descending.
              优先考虑 A。

              The idea is that you can apply -sign in order function ony on numericals. So for sorting character strings in descending order you have to coerce them to numericals.

              【讨论】:

                【解决方案9】:

                在@dudusan的例子中,你也可以把I1的顺序倒过来,然后升序排序:

                > rum <- read.table(textConnection("P1  P2  P3  T1  T2  T3  I1  I2
                +   2   3   5   52  43  61  6   b
                +   6   4   3   72  NA  59  1   a
                +   1   5   6   55  48  60  6   f
                +   2   4   4   65  64  58  2   b
                +   1   5   6   55  48  60  6   c"), header = TRUE)
                > f=factor(rum$I1)   
                > levels(f) <- sort(levels(f), decreasing = TRUE)
                > rum[order(as.character(f), rum$I2), ]
                  P1 P2 P3 T1 T2 T3 I1 I2
                1  2  3  5 52 43 61  6  b
                5  1  5  6 55 48 60  6  c
                3  1  5  6 55 48 60  6  f
                4  2  4  4 65 64 58  2  b
                2  6  4  3 72 NA 59  1  a
                > 
                

                这似乎有点短,你不要将I2的顺序颠倒两次。

                【讨论】:

                  【解决方案10】:

                  我用rank:

                  rum <- read.table(textConnection("P1  P2  P3  T1  T2  T3  I1  I2
                  2   3   5   52  43  61  6   b
                  6   4   3   72  NA  59  1   a
                  1   5   6   55  48  60  6   f
                  2   4   4   65  64  58  2   b
                  1   5   6   55  48  60  6   c"), header = TRUE)
                  
                  > rum[order(rum$I1, -rank(rum$I2), decreasing = TRUE), ]
                    P1 P2 P3 T1 T2 T3 I1 I2
                  1  2  3  5 52 43 61  6  b
                  5  1  5  6 55 48 60  6  c
                  3  1  5  6 55 48 60  6  f
                  4  2  4  4 65 64 58  2  b
                  2  6  4  3 72 NA 59  1  a
                  

                  【讨论】:

                  • 简单的没有等级的:rum[order(rum$I1, -rum$I2, reduction = TRUE), ]
                  • 谢谢,帮我订购了我的日期栏(这不适用于 -)
                  • @SomnathKadam 减号在字符向量前不起作用 -c("a") 返回错误
                  【解决方案11】:

                  恐怕 Roman Luštrik 的回答是错误的。它偶然在这个输入上起作用。 例如,考虑它在非常相似的输入上的输出(与原始第 3 行类似的附加行,在 I2 列中带有“c”):

                  rum <- read.table(textConnection("P1  P2  P3  T1  T2  T3  I1  I2
                  2   3   5   52  43  61  6   b
                  6   4   3   72  NA  59  1   a
                  1   5   6   55  48  60  6   f
                  2   4   4   65  64  58  2   b
                  1   5   6   55  48  60  6   c"), header = TRUE)
                  
                  rum$I2 <- as.character(rum$I2)
                  rum[order(rum$I1, rev(rum$I2), decreasing = TRUE), ]
                  
                    P1 P2 P3 T1 T2 T3 I1 I2
                  3  1  5  6 55 48 60  6  f
                  1  2  3  5 52 43 61  6  b
                  5  1  5  6 55 48 60  6  c
                  4  2  4  4 65 64 58  2  b
                  2  6  4  3 72 NA 59  1  a
                  

                  这不是预期的结果:I2 的前三个值是 f b c 而不是 b c f,这是意料之中的,因为二级排序是 I2 按升序排列。

                  要获得 I2 的相反顺序,您希望较大的值较小,反之亦然。对于数值乘以 -1 就可以了,但是对于字符来说它有点棘手。字符/字符串的一般解决方案是遍历因子,反转级别(使大值变小,小值变大)并将因子改回字符:

                  rum <- read.table(textConnection("P1  P2  P3  T1  T2  T3  I1  I2
                  2   3   5   52  43  61  6   b
                  6   4   3   72  NA  59  1   a
                  1   5   6   55  48  60  6   f
                  2   4   4   65  64  58  2   b
                  1   5   6   55  48  60  6   c"), header = TRUE)
                  
                  f=factor(rum$I2)
                  levels(f) = rev(levels(f))
                  rum[order(rum$I1, as.character(f), decreasing = TRUE), ]
                  
                    P1 P2 P3 T1 T2 T3 I1 I2
                  1  2  3  5 52 43 61  6  b
                  5  1  5  6 55 48 60  6  c
                  3  1  5  6 55 48 60  6  f
                  4  2  4  4 65 64 58  2  b
                  2  6  4  3 72 NA 59  1  a
                  

                  【讨论】:

                  • 查看 Michele 的答案,这似乎有效,而且比我自己的更直接。
                  【解决方案12】:

                  正确的做法是:

                  rum[order(rum$T1, rum$T2, decreasing=c(T,F)), ]
                  

                  【讨论】:

                  • 这会非常简洁,但似乎不起作用:将 Roman Luštrik 的 rum[order(rum$I1, rev(rum$I2), decreasing = TRUE), ] 的输出与您的 rum[order(rum$I1, rum$I2, decreasing = c(TRUE, FALSE)), ] 进行比较。我不认为decreasing 接受值向量。
                  • 这是错误的。递减不接受向量,不应该依赖这个答案。
                  • 这实际上可以工作(至少在 R 3.4.0 中),因为默认的 method="auto" 将使用 "radix" 来表示“短数值向量、整数向量、逻辑向量和因子”,以及 @987654328当使用"radix" 时,@ 可以是向量。请参阅文档here
                  【解决方案13】:

                  我使用此代码生成您想要的输出。这就是你所追求的吗?

                  rum <- read.table(textConnection("P1  P2  P3  T1  T2  T3  I1  I2
                  2   3   5   52  43  61  6   b
                  6   4   3   72  NA  59  1   a
                  1   5   6   55  48  60  6   f
                  2   4   4   65  64  58  2   b"), header = TRUE)
                  rum$I2 <- as.character(rum$I2)
                  rum[order(rum$I1, rev(rum$I2), decreasing = TRUE), ]
                  
                    P1 P2 P3 T1 T2 T3 I1 I2
                  1  2  3  5 52 43 61  6  b
                  3  1  5  6 55 48 60  6  f
                  4  2  4  4 65 64 58  2  b
                  2  6  4  3 72 NA 59  1  a
                  

                  【讨论】:

                  • 谢谢。我仍然对 R 所拥有的一切感到不知所措,并且不知道 rev 函数。同时,我发现如果第二个向量是数字,我可以通过 max 减去向量来排序,但是在你回答之前,字符向量仍然是一个问题。
                  • @rumtscho 是的,这就是我在订单帮助文件中的做法,这是我的灵感来源。 ;)
                  • 请务必查看@dudusan 的答案,了解此方法会失败的数据。问题是使用 rev() 不再将行保持在一起,它只是将列颠倒过来。它只在这种情况下有效,因为这个例子被“很好地”安排了。
                  • 请看下面@dudusan 的回答,很遗憾这个回答不正确!
                  猜你喜欢
                  • 1970-01-01
                  • 2021-06-10
                  • 2020-11-09
                  • 2018-05-03
                  • 1970-01-01
                  • 2021-10-25
                  • 2016-10-18
                  • 2023-03-13
                  相关资源
                  最近更新 更多