8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

按多列对数据框行进行排序(排序)

MSchmidt 2月前

273 0

我想按多列对数据框进行排序。例如,对于下面的数据框,我想按列“z”(降序)排序,然后按列“b”(升序)排序:dd <- data.frame(b = facto...

我想按多列对数据框进行排序。例如,对于下面的数据框,我想按列“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
帖子版权声明 1、本帖标题:按多列对数据框行进行排序(排序)
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由MSchmidt在本站《sorting》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 您可以直接使用 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
    

    两年多后编辑: 只是有人问如何通过列索引执行此操作。答案是只需将所需的排序列传递给函数 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() 为了更容易/更直接的访问)。

  • 应该以相同的方式工作,但不能使用。尝试 M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c(\'a\',\'b\'))) 创建矩阵 M,然后使用 M[order(M[,\'a\'],-M[,\'b\']),] 按两列对其进行排序。

  • 足够简单:dd[ order(-dd[,4], dd[,1]), ],但不能用于基于名称的子集。

  • 为什么 dd[ order(-dd[,4],, ] 无效或 'dd[ order(-dd[,4], ]' 基本上为什么需要 dd[,1]?如果只想按 1 列排序,-dd[,4] 是否还不够?

  • 当您对字符列使用减号时,会出现“一元运算符的参数无效”错误。通过在 xtfrm 中包装列来解决此问题,例如 dd[ order(-xtfrm(dd[,4]), dd[,1]), ]。

  • 您的选择

    • order base
    • arrange dplyr
    • setorder 以及 setorderv 来自 data.table
    • arrange plyr
    • sort taRifx
    • orderBy doBy
    • sortData Deducer

    大多数情况下,你应该使用 dplyr data.table 解决方案,除非没有依赖关系很重要,在这种情况下使用 base::order .


    我最近将 sort.data.frame 添加到了 CRAN 包中,使其与这里讨论的类兼容: 为 sort.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 )
    

    如果您是此功能的原作者之一,请联系我。有关公共领域的讨论在此处: https://chat..com/transcript/message/1094290#1094290


    您还可以使用 arrange() Hadley 在上面的线程中指出的 plyr 功能

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

    基准测试:请注意,由于存在许多冲突,我将每个包都加载到新的 R 会话中。特别是,加载 doBy 包会导致 sort 返回“以下对象被‘x(位置 17)’屏蔽:b、x、y、z”,而加载 Deducer 包会覆盖 sort.data.frame Kevin Wright 或 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)
    

    由于附加/分离,似乎与微基准测试不兼容。


    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))
    

    microbenchmark plot

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


    鉴于这些结果,并在简单性和速度之间进行权衡,我不得不同意 arrange in the plyr package 。它的语法简单,但速度却几乎与基本 R 命令及其复杂的机制一样快。典型的 Hadley Wickham 作品。我唯一不满意的是,它打破了标准 R 命名法,其中排序对象由 调用 sort(object) ,但我理解 Hadley 这样做的原因,因为上面链接的问题中讨论了这些问题。

  • 上面的 ggplot2 microbenchmark 函数现在可以作为 taRifx::autoplot.microbenchmark 使用。

  • @AriB.Friedman 使用“arrange”,我们如何按升序排序?我从未见过按升序排序的示例。我尝试使用“asc”而不是“desc”,但它不起作用。谢谢

  • @AME 看看样本中 b 是如何排序的。默认按升序排序,因此您不必将其包装在 desc 中。两者均按升序排列:arrange(dd,z,b)。两者均按降序排列:arrange(dd,desc(z),desc(b))。

  • 根据 ?arrange: \'# NOTE: plyr 函数不保留 row.names\'。如果想要保留 row.names,这会使优秀的 accordion() 函数变得不理想。

  • 如果您改用 sort.list(x, method=“radix”),其中一些使用顺序可能会更快一些。

  • Dirk 的回答很棒。它还强调了索引 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 根本 with() 不需要

    代替

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

    只是

    dd[order(-z, b)]
    

    而不是

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

    只是

    quarterlyreport[order(-z,b)]
    

    这是一个很小的差异,但有一天它可能会救你一命。在权衡这个问题的不同答案时,请考虑将变量名称的重复次数作为决定的标准之一。有些答案有相当多的重复,而其他答案则没有。

  • +1 这是一个很好的观点,并且指出了 R 语法中经常让我恼火的细节。我有时使用 subset() 只是为了避免在一次调用中重复引用同一个对象。

  • 我想您也可以在这里添加新的 setorder 函数,因为这个线程是我们发送所有订单类型重复的地方。

  • 这里有很多优秀的答案,但是 dplyr 给出了我能快速轻松记住的唯一语法(所以现在经常使用):

    library(dplyr)
    # sort mtcars by mpg, ascending... use desc(mpg) for descending
    arrange(mtcars, mpg)
    # sort mtcars first by mpg, then by cyl, then by wt)
    arrange(mtcars , mpg, cyl, wt)
    

    对于OP的问题:

    arrange(dd, desc(z),  b)
    
        b x y z
    1 Low C 9 2
    2 Med D 3 1
    3  Hi A 8 1
    4  Hi A 9 1
    
  • 当我的列是或类型因子(或类似的东西)并且我想按降序排列此因子列,然后按升序排列整数列时,接受的答案不起作用。但这很好用!谢谢!

  • 为什么是“仅”?我发现 data.table 的 dd[order(-z, b)] 非常容易使用和记住。

  • 同意,这两种方法之间没有太大区别,而且 data.table 在很多其他方面也为 R 做出了巨大贡献。我认为,对我来说,在这种情况下,少一组括号(或少一种括号)可能会减少几乎不可察觉的认知负担。

  • 对我来说,事实是,arrange() 是完全声明性的,而 dd[order(-z, b)] 不是。

返回
作者最近主题: