如何按多个列排序数据框?

我想通过多列对数据框进行排序。 例如,在下面的data.frame中,我想按列z (降序)然后按列b (升序)排序:

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
dd
    b x y z
1  Hi A 8 1
2 Med D 3 1
3  Hi A 9 1
4 Low C 9 2

您可以直接使用order()函数,而无需借助附加工具 - 查看这个更简单的答案,它使用example(order)代码顶部的一个技巧:

R> dd[with(dd, order(-z, b)), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

一些2+年后编辑:它只是被问及如何通过列索引来做到这一点。 答案是简单地将所需的排序列传递给order()函数:

R> dd[ order(-dd[,4], dd[,1]), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
R> 

而不是使用列的名称(和with()以便于更直接地访问)。


您的选择

  • orderbase
  • dplyr arrange
  • setordersetordervdata.table
  • plyr arrange
  • taRifx sort
  • orderBydoBy
  • sortDataDeducer
  • 大多数情况下,您应该使用dplyrdata.table解决方案,除非没有依赖关系很重要,在这种情况下使用base::order


    我最近将sort.data.frame添加到一个CRAN包中,使其与类的兼容性如下所述:为sort.data.frame创建泛型/方法一致性的最佳方法?

    因此,给定data.frame dd,你可以按如下方式排序:

    dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
          levels = c("Low", "Med", "Hi"), ordered = TRUE),
          x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
          z = c(1, 1, 1, 2))
    library(taRifx)
    sort(dd, f= ~ -z + b )
    

    如果您是此功能的原创作者之一,请与我联系。 关于公共领域的讨论在这里:http://chat.stackoverflow.com/transcript/message/1094290#1094290


    您也可以使用Hadley在上述线程中指出的plyrarrange()函数:

    library(plyr)
    arrange(dd,desc(z),b)
    

    基准测试:请注意,由于存在很多冲突,我在一个新的R会话中加载了每个软件包。 特别是加载doBy包导致sort返回“下面的对象从'x(位置17)'被掩盖:b,x,y,z”,并且加载Deducer包将覆盖来自Kevin的sort.data.frame赖特或taRifx包。

    #Load each time
    dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
          levels = c("Low", "Med", "Hi"), ordered = TRUE),
          x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
          z = c(1, 1, 1, 2))
    library(microbenchmark)
    
    # Reload R between benchmarks
    microbenchmark(dd[with(dd, order(-z, b)), ] ,
        dd[order(-dd$z, dd$b),],
        times=1000
    )
    

    平均时间:

    dd[with(dd, order(-z, b)), ] 778

    dd[order(-dd$z, dd$b),] 788

    library(taRifx)
    microbenchmark(sort(dd, f= ~-z+b ),times=1000)
    

    中位时间: 1,567

    library(plyr)
    microbenchmark(arrange(dd,desc(z),b),times=1000)
    

    中位时间: 862

    library(doBy)
    microbenchmark(orderBy(~-z+b, data=dd),times=1000)
    

    中位时间: 1,694

    请注意,doBy需要很长时间才能加载包。

    library(Deducer)
    microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)
    

    无法使Deducer载入。 需要JGR控制台。

    esort <- function(x, sortvar, ...) {
    attach(x)
    x <- x[with(x,order(sortvar,...)),]
    return(x)
    detach(x)
    }
    
    microbenchmark(esort(dd, -z, b),times=1000)
    

    由于附着/分离,似乎与microbenchmark不兼容。


    m <- microbenchmark(
      arrange(dd,desc(z),b),
      sort(dd, f= ~-z+b ),
      dd[with(dd, order(-z, b)), ] ,
      dd[order(-dd$z, dd$b),],
      times=1000
      )
    
    uq <- function(x) { fivenum(x)[4]}  
    lq <- function(x) { fivenum(x)[2]}
    
    y_min <- 0 # min(by(m$time,m$expr,lq))
    y_max <- max(by(m$time,m$expr,uq)) * 1.05
    
    p <- ggplot(m,aes(x=expr,y=time)) + coord_cartesian(ylim = c( y_min , y_max )) 
    p + stat_summary(fun.y=median,fun.ymin = lq, fun.ymax = uq, aes(fill=expr))
    

    (线从下四分位延伸到上四分位,点是中位数)


    鉴于这些结果和称重简单性与速度,我不得不点头表示arrangeplyr包装中 。 它有一个简单的语法,但它的基本R命令与它们的复杂旋转几乎一样快。 典型的辉煌哈德利韦克汉姆的工作。 我唯一抱怨的是,它打破了标准R命名法,其中按sort(object)排序对象进行调用,但是我明白为什么Hadley会这样做,因为上面链接问题中讨论的问题。


    德克的回答很好。 它还强调了用于索引data.frame s和data.table s的语法中的一个关键区别:

    ## The data.frame way
    dd[with(dd, order(-z, b)), ]
    
    ## The data.table way: (7 fewer characters, but that's not the important bit)
    dd[order(-z, b)]
    

    这两个电话之间的差别很小,但它可能会产生重要的后果。 特别是如果您在研究中编写产品代码和/或关心正确性,最好避免不必要的重复变量名称。 data.table帮助你做到这一点。

    下面是一个重复变量名称可能会让你陷入麻烦的例子:

    让我们从Dirk的回答中改变上下文,并说这是更大项目的一部分,其中有很多对象名称,而且它们很长且有意义。 而不是dd它被称为quarterlyreport 。 它成为了 :

    quarterlyreport[with(quarterlyreport,order(-z,b)),]
    

    好的。 没有错。 接下来你的老板会要求你在报告中包含上个季度的报告。 你走你的代码,添加对象lastquarterlyreport在不同的地方,不知怎么你结束了这个(如何在地球上?):

    quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
    

    这不是你的意思,但你没有发现它,因为你做得很快,而且它依赖于类似代码的页面。 代码不会翻倒(没有警告和错误),因为R认为它是你的意思。 你希望看到你的报告的人看到它,但也许他们没有。 如果你使用编程语言很多,那么这种情况可能会让人很熟悉。 这是一个你会说的“打​​字错误”。 我会解决你对老板说的“打字错误”。

    data.table我们关注这样的细节。 所以我们做了一些简单的事情来避免两次输入变量名。 一些非常简单的东西。 i已经自动地在dd帧内dd进行了评估。 with()完全不需要。

    代替

    dd[with(dd, order(-z, b)), ]
    

    只是

    dd[order(-z, b)]
    

    而不是

    quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
    

    只是

    quarterlyreport[order(-z,b)]
    

    这是一个非常小的差异,但它可能只会挽救你的脖子有一天。 在权衡这个问题的不同答案时,考虑将变量名称的重复计为您决定的标准之一。 有些答案有不少重复,其他答案没有。

    链接地址: http://www.djcxy.com/p/1913.html

    上一篇: How to sort a dataframe by multiple column(s)?

    下一篇: How do I sort an NSMutableArray with custom objects in it?