【问题标题】:Sort (order) data frame rows by multiple columns按多列对数据框行进行排序(排序)
【发布时间】:2010-11-20 18:21:42
【问题描述】:

我想按多列对数据框进行排序。例如,对于下面的数据框,我想按列“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

【问题讨论】:

    标签: r sorting dataframe r-faq


    【解决方案1】:

    dplyr 中的arrange() 是我最喜欢的选项。使用管道运算符,从最不重要的方面到最重要的方面

    dd1 <- dd %>%
        arrange(z) %>%
        arrange(desc(x))
    

    【讨论】:

      【解决方案2】:

      如果 SQL 对您来说很自然,sqldf 包会按照 Codd 的意图处理 ORDER BY

      【讨论】:

      • MJM,感谢您指出这个包。它非常灵活,因为我的一半工作已经通过从 sql 数据库中提取完成,所以比学习 R 的很多不直观的语法要容易。
      【解决方案3】:

      您的选择

      • order 来自base
      • arrange 来自dplyr
      • setordersetorderv 来自 data.table
      • arrange 来自plyr
      • sort 来自taRifx
      • orderBy 来自doBy
      • sortData 来自Deducer

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


      我最近将 sort.data.frame 添加到 CRAN 包中,使其类兼容,如下所述: Best way to create generic/method consistency for 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 )
      

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


      您还可以使用 plyr 中的 arrange() 函数,正如 Hadley 在上述线程中指出的那样:

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

      基准测试:请注意,我在新的 R 会话中加载了每个包,因为存在很多冲突。特别是加载 doBy 包会导致 sort 返回“以下对象被'x(位置 17)'屏蔽:b、x、y、z”,并且加载 Deducer 包会覆盖来自 Kevin 的 sort.data.frame 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))
      

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


      鉴于这些结果并权衡简单性与速度,我不得不向plyr 包中的arrange 表示赞同。它具有简单的语法,但几乎与带有复杂机制的基本 R 命令一样快。通常出色的哈德利·威克姆(Hadley Wickham)作品。我唯一的抱怨是它打破了标准 R 命名法,其中排序对象由sort(object) 调用,但我理解为什么 Hadley 这样做是因为上面链接的问题中讨论的问题。

      【讨论】:

      • 上面的 ggplot2 微基准函数现在可以作为taRifx::autoplot.microbenchmark使用。
      • @AriB.Friedman 使用“排列”,我们如何按升序排序?我从未见过按升序排序的示例。我尝试了“asc”而不是“desc”,但它不起作用。谢谢
      • @AME 查看b 在示例中的排序方式。默认是升序排序,所以你不要把它包装在desc中。两者都升序:arrange(dd,z,b)。两者都降序:arrange(dd,desc(z),desc(b))
      • 根据?arrange:“# 注意:plyr 函数不保留 row.names”。如果想要保留row.names,这使得出色的arrange() 功能不是最理想的。
      • 如果你改用sort.list(x, method=“radix”),其中一些使用order的可能会快一些。
      【解决方案4】:

      只是为了完整起见,因为关于按列号排序的说法并不多……可以肯定地说,这通常是不可取的(因为列的顺序可能会改变,从而为错误铺平道路),但在某些特定情况下(例如,当您需要快速完成工作并且不存在列更改顺序的风险时),这可能是最明智的做法,尤其是在处理大量列时。

      在这种情况下,do.call() 来救援:

      ind <- do.call(what = "order", args = iris[,c(5,1,2,3)])
      iris[ind, ]
      
      ##        Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
      ##    14           4.3         3.0          1.1         0.1     setosa
      ##    9            4.4         2.9          1.4         0.2     setosa
      ##    39           4.4         3.0          1.3         0.2     setosa
      ##    43           4.4         3.2          1.3         0.2     setosa
      ##    42           4.5         2.3          1.3         0.3     setosa
      ##    4            4.6         3.1          1.5         0.2     setosa
      ##    48           4.6         3.2          1.4         0.2     setosa
      ##    7            4.6         3.4          1.4         0.3     setosa
      ##    (...)
      

      【讨论】:

        【解决方案5】:

        当我想自动化我的 n 列的排序过程时,我一直在为上述解决方案苦苦挣扎,这些列的名称每次都可能不同。我从 psych 包中找到了一个非常有用的功能,可以直接完成此操作:

        dfOrder(myDf, columnIndices)
        

        其中columnIndices 是一列或多列的索引,按照您希望对它们进行排序的顺序。更多信息在这里:

        dfOrder function from 'psych' package

        【讨论】:

          【解决方案6】:

          您可以直接使用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() 以便更轻松/更直接地访问)。

          【讨论】:

          • 应该以同样的方式工作,但你不能使用with。尝试M &lt;- 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]), ],但不能将with 用于基于名称的子集。
          • 为什么dd[ order(-dd[,4],, ] 无效或 'dd[ order(-dd[,4], ]' 基本上为什么需要dd[,1]?如果您只想排序,-dd[,4] 还不够吗? 1 列?
          • 在字符列中使用减号时会出现“一元运算符的参数无效”错误。通过将列包装在xtfrm 中来解决它,例如dd[ order(-xtfrm(dd[,4]), dd[,1]), ]
          【解决方案7】:

          另一种选择,使用rgr 包:

          > library(rgr)
          > gx.sort.df(dd, ~ -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
          

          【讨论】:

            【解决方案8】:

            使用this (very helpful) function by Kevin Wright,发布在 R wiki 的提示部分,这很容易实现。

            sort(dd,by = ~ -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
            

            【讨论】:

              【解决方案9】:

              响应 OP 中添加的关于如何以编程方式排序的评论:

              使用dplyrdata.table

              library(dplyr)
              library(data.table)
              

              dplyr

              只需使用arrange_,这是arrange 的标准评估版本。

              df1 <- tbl_df(iris)
              #using strings or formula
              arrange_(df1, c('Petal.Length', 'Petal.Width'))
              arrange_(df1, ~Petal.Length, ~Petal.Width)
                  Source: local data frame [150 x 5]
              
                 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
                        (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
              1           4.6         3.6          1.0         0.2  setosa
              2           4.3         3.0          1.1         0.1  setosa
              3           5.8         4.0          1.2         0.2  setosa
              4           5.0         3.2          1.2         0.2  setosa
              5           4.7         3.2          1.3         0.2  setosa
              6           5.4         3.9          1.3         0.4  setosa
              7           5.5         3.5          1.3         0.2  setosa
              8           4.4         3.0          1.3         0.2  setosa
              9           5.0         3.5          1.3         0.3  setosa
              10          4.5         2.3          1.3         0.3  setosa
              ..          ...         ...          ...         ...     ...
              
              
              #Or using a variable
              sortBy <- c('Petal.Length', 'Petal.Width')
              arrange_(df1, .dots = sortBy)
                  Source: local data frame [150 x 5]
              
                 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
                        (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
              1           4.6         3.6          1.0         0.2  setosa
              2           4.3         3.0          1.1         0.1  setosa
              3           5.8         4.0          1.2         0.2  setosa
              4           5.0         3.2          1.2         0.2  setosa
              5           4.7         3.2          1.3         0.2  setosa
              6           5.5         3.5          1.3         0.2  setosa
              7           4.4         3.0          1.3         0.2  setosa
              8           4.4         3.2          1.3         0.2  setosa
              9           5.0         3.5          1.3         0.3  setosa
              10          4.5         2.3          1.3         0.3  setosa
              ..          ...         ...          ...         ...     ...
              
              #Doing the same operation except sorting Petal.Length in descending order
              sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
              arrange_(df1, .dots = sortByDesc)
              

              更多信息在这里:https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html

              最好使用公式,因为它还可以捕获环境来评估表达式

              数据表

              dt1 <- data.table(iris) #not really required, as you can work directly on your data.frame
              sortBy <- c('Petal.Length', 'Petal.Width')
              sortType <- c(-1, 1)
              setorderv(dt1, sortBy, sortType)
              dt1
                   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
                1:          7.7         2.6          6.9         2.3 virginica
                2:          7.7         2.8          6.7         2.0 virginica
                3:          7.7         3.8          6.7         2.2 virginica
                4:          7.6         3.0          6.6         2.1 virginica
                5:          7.9         3.8          6.4         2.0 virginica
               ---                                                            
              146:          5.4         3.9          1.3         0.4    setosa
              147:          5.8         4.0          1.2         0.2    setosa
              148:          5.0         3.2          1.2         0.2    setosa
              149:          4.3         3.0          1.1         0.1    setosa
              150:          4.6         3.6          1.0         0.2    setosa
              

              【讨论】:

                【解决方案10】:

                为了完整起见:您还可以使用BBmisc 包中的sortByCol() 函数:

                library(BBmisc)
                sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE))
                    b x y z
                4 Low C 9 2
                2 Med D 3 1
                1  Hi A 8 1
                3  Hi A 9 1
                

                性能对比:

                library(microbenchmark)
                microbenchmark(sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE)), times = 100000)
                median 202.878
                
                library(plyr)
                microbenchmark(arrange(dd,desc(z),b),times=100000)
                median 148.758
                
                microbenchmark(dd[with(dd, order(-z, b)), ], times = 100000)
                median 115.872
                

                【讨论】:

                • 奇怪的是,当您的方法最慢时添加性能比较......无论如何,在 4 行 data.frame987654325@ 上使用基准测试的价值值得怀疑
                【解决方案11】:

                R 包data.table 提供快速内存高效data.tables 排序,语法简单(其中一部分马特很好地突出了in his answer)。从那时起,已经有了很多改进,还有一个新功能setorder()。从v1.9.5+setorder() 也适用于data.frames

                首先,我们将创建一个足够大的数据集,并对其他答案中提到的不同方法进行基准测试,然后列出 data.table 的特征。

                数据:

                require(plyr)
                require(doBy)
                require(data.table)
                require(dplyr)
                require(taRifx)
                
                set.seed(45L)
                dat = data.frame(b = as.factor(sample(c("Hi", "Med", "Low"), 1e8, TRUE)),
                                 x = sample(c("A", "D", "C"), 1e8, TRUE),
                                 y = sample(100, 1e8, TRUE),
                                 z = sample(5, 1e8, TRUE), 
                                 stringsAsFactors = FALSE)
                

                基准测试:

                报告的时间来自在下面显示的这些函数上运行 system.time(...)。时间如下表所示(按从慢到快的顺序)。

                orderBy( ~ -z + b, data = dat)     ## doBy
                plyr::arrange(dat, desc(z), b)     ## plyr
                arrange(dat, desc(z), b)           ## dplyr
                sort(dat, f = ~ -z + b)            ## taRifx
                dat[with(dat, order(-z, b)), ]     ## base R
                
                # convert to data.table, by reference
                setDT(dat)
                
                dat[order(-z, b)]                  ## data.table, base R like syntax
                setorder(dat, -z, b)               ## data.table, using setorder()
                                                   ## setorder() now also works with data.frames 
                
                # R-session memory usage (BEFORE) = ~2GB (size of 'dat')
                # ------------------------------------------------------------
                # Package      function    Time (s)  Peak memory   Memory used
                # ------------------------------------------------------------
                # doBy          orderBy      409.7        6.7 GB        4.7 GB
                # taRifx           sort      400.8        6.7 GB        4.7 GB
                # plyr          arrange      318.8        5.6 GB        3.6 GB 
                # base R          order      299.0        5.6 GB        3.6 GB
                # dplyr         arrange       62.7        4.2 GB        2.2 GB
                # ------------------------------------------------------------
                # data.table      order        6.2        4.2 GB        2.2 GB
                # data.table   setorder        4.5        2.4 GB        0.4 GB
                # ------------------------------------------------------------
                
                • data.tableDT[order(...)] 语法比其他最快的方法 (dplyr) 快 ~10 倍,同时消耗的内存量与 dplyr 相同。

                • data.tablesetorder() 比其他最快的方法 (dplyr) 快 ~14 倍,同时占用 仅 0.4GB 额外内存dat 现在是我们需要的顺序(因为它是通过引用更新的)。

                data.table 特征:

                速度:

                • data.table 的排序非常快,因为它实现了radix ordering

                • DT[order(...)] 语法在内部进行了优化,以使用 data.table 的快速排序。您可以继续使用熟悉的基本 R 语法,但会加快进程(并使用更少的内存)。

                内存:

                • 大多数时候,我们不需要重新排序后的原始 data.framedata.table。也就是我们通常将结果赋值回同一个对象,例如:

                  DF <- DF[order(...)]
                  

                  问题在于,这至少需要原始对象的两倍 (2x) 内存。为了内存效率data.table因此也提供了一个函数setorder()

                  setorder() 重新排序 data.tables by reference就地),而无需制作任何额外的副本。它只使用等于一列大小的额外内存。

                其他功能:

                1. 它支持integerlogicalnumericcharacter甚至bit64::integer64类型。

                  请注意,factorDatePOSIXct 等类都是 integer/numeric 类型,带有附加属性,因此也受支持。

                2. 在基础 R 中,我们不能在字符向量上使用 - 来按该列按降序排序。相反,我们必须使用-xtfrm(.)

                  但是,在 data.table 中,我们可以这样做,例如,dat[order(-x)]setorder(dat, -x)

                【讨论】:

                • 感谢这个关于 data.table 的非常有启发性的回答。不过,我不明白什么是“峰值记忆”以及您如何计算它。你能解释一下吗?谢谢!
                • 我使用了Instruments -> 分配并报告了“所有堆和分配虚拟机”的大小。
                • @Arun 您评论中的 Instruments 链接已失效。想发布更新吗?
                • @MichaelChirico 以下是有关 Apple 制造的 Instruments 信息的链接:developer.apple.com/library/content/documentation/…
                【解决方案12】:

                就像很久以前的机械卡片分类器一样,首先按最不重要的键排序,然后是下一个最重要的键,等等。不需要库,可以使用任意数量的键以及升序和降序键的任意组合。

                 dd <- dd[order(dd$b, decreasing = FALSE),]
                

                现在我们已准备好执行最重要的密钥。排序是稳定的,并且最重要的键中的任何关系都已经解决了。

                dd <- dd[order(dd$z, decreasing = TRUE),]
                

                这可能不是最快的,但肯定简单可靠

                【讨论】:

                  【解决方案13】:

                  我通过以下示例了解了order,这让我困惑了很长时间:

                  set.seed(1234)
                  
                  ID        = 1:10
                  Age       = round(rnorm(10, 50, 1))
                  diag      = c("Depression", "Bipolar")
                  Diagnosis = sample(diag, 10, replace=TRUE)
                  
                  data = data.frame(ID, Age, Diagnosis)
                  
                  databyAge = data[order(Age),]
                  databyAge
                  

                  此示例有效的唯一原因是因为order 是按vector Age 排序的,而不是按data frame data 中名为Age 的列。

                  要查看这一点,使用 read.table 创建一个相同的数据框,列名略有不同,并且不使用上述任何向量:

                  my.data <- read.table(text = '
                  
                    id age  diagnosis
                     1  49 Depression
                     2  50 Depression
                     3  51 Depression
                     4  48 Depression
                     5  50 Depression
                     6  51    Bipolar
                     7  49    Bipolar
                     8  49    Bipolar
                     9  49    Bipolar
                    10  49 Depression
                  
                  ', header = TRUE)
                  

                  order 的上述行结构不再有效,因为没有名为 age 的向量:

                  databyage = my.data[order(age),]
                  

                  以下行有效,因为ordermy.data 中的age 列进行排序。

                  databyage = my.data[order(my.data$age),]
                  

                  鉴于我对这个例子很困惑这么久,我认为这是值得发布的。如果这篇文章被认为不适合该主题,我可以将其删除。

                  编辑:2014 年 5 月 13 日

                  以下是按每一列对数据框进行排序的通用方法,无需指定列名。下面的代码显示了如何从左到右或从右到左排序。如果每列都是数字,则此方法有效。我没有尝试添加字符列。

                  我在一两个月前在另一个网站上的一篇旧帖子中找到了do.call 代码,但只是在经过广泛而艰难的搜索之后。我不确定我现在是否可以重新定位该职位。当前线程是在R 中订购data.frame 的第一个热门话题。所以,我认为我的原始 do.call 代码的扩展版本可能有用。

                  set.seed(1234)
                  
                  v1  <- c(0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1)
                  v2  <- c(0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1)
                  v3  <- c(0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1)
                  v4  <- c(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1)
                  
                  df.1 <- data.frame(v1, v2, v3, v4) 
                  df.1
                  
                  rdf.1 <- df.1[sample(nrow(df.1), nrow(df.1), replace = FALSE),]
                  rdf.1
                  
                  order.rdf.1 <- rdf.1[do.call(order, as.list(rdf.1)),]
                  order.rdf.1
                  
                  order.rdf.2 <- rdf.1[do.call(order, rev(as.list(rdf.1))),]
                  order.rdf.2
                  
                  rdf.3 <- data.frame(rdf.1$v2, rdf.1$v4, rdf.1$v3, rdf.1$v1) 
                  rdf.3
                  
                  order.rdf.3 <- rdf.1[do.call(order, as.list(rdf.3)),]
                  order.rdf.3
                  

                  【讨论】:

                  • 如果您将数据存储在 data.table 而不是 data.frame 中,则该语法确实有效:require(data.table); my.dt &lt;- data.table(my.data); my.dt[order(age)] 这是有效的,因为列名在 [] 括号内可用。跨度>
                  • 我认为这里没有必要投反对票,但我认为这也不会增加手头的问题,特别是考虑到现有的一组答案,其中一些已经使用data.frames 捕获了使用with$ 的要求。
                  • do.call 投票,这使得排序多列数据框的工作变得很短。只需do.call(sort, mydf.obj) 就会有一个漂亮的级联排序。
                  【解决方案14】:

                  这里有很多优秀的答案,但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)] 不是。
                  【解决方案15】:

                  德克的回答很棒。它还强调了用于索引data.frames 和data.tables 的语法的关键区别:

                  ## 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 函数,因为这个线程是我们发送所有order 类型欺骗的地方。
                  【解决方案16】:

                  假设您有一个 data.frame A 并且您想使用名为 x 的列降序对其进行排序。调用排序后的data.framenewdata

                  newdata <- A[order(-A$x),]
                  

                  如果您想要升序,则将"-" 替换为空。你可以有类似的东西

                  newdata <- A[order(-A$x, A$y, -A$z),]
                  

                  其中xzdata.frame A 中的一些列。这意味着按x 降序、y 升序和z 降序对data.frame A 进行排序。

                  【讨论】:

                    【解决方案17】:

                    Dirk 的回答很好,但如果您需要排序持久化,您需要将排序应用回该数据框的名称。使用示例代码:

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

                    【讨论】:

                      【解决方案18】:

                      或者你可以使用包doBy

                      library(doBy)
                      dd <- orderBy(~-z+b, data=dd)
                      

                      【讨论】:

                        【解决方案19】:

                        或者,使用包 Deducer

                        library(Deducer)
                        dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
                        

                        【讨论】:

                          猜你喜欢
                          • 2021-03-27
                          • 2022-11-12
                          • 1970-01-01
                          • 1970-01-01
                          • 2021-10-29
                          • 1970-01-01
                          • 2018-06-25
                          相关资源
                          最近更新 更多