如何按多列对数据帧进行排序?

Chr*_*ois 1266 sorting r dataframe r-faq

我想按多列对data.frame进行排序.例如,对于下面的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
Run Code Online (Sandbox Code Playgroud)

Dir*_*tel 1575

您可以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
Run Code Online (Sandbox Code Playgroud)

大约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> 
Run Code Online (Sandbox Code Playgroud)

而不是使用列的名称(with()以便更容易/更直接访问).

  • 我在运行第二个例子时遇到"一元运算符的无效参数"错误. (18认同)
  • 使用带有字符列的减号时,会出现"一元运算符的无效参数"错误.通过将列包装在`xtfrm`中来解决它,例如`dd [order(-xtfrm(dd [,4]),dd [,1]),]`. (18认同)
  • 应该以同样的方式工作,但你不能使用`with`.尝试`M < - 矩阵(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"]),]`来命令它在两列上. (13认同)
  • 足够简单:`dd [order(-dd [,4],dd [,1]),]`,但不能使用`with`进行基于名称的子集化. (4认同)

Ari*_*man 447

你的选择

  • orderbase
  • arrangedplyr
  • setordersetordervdata.table
  • arrangeplyr
  • sorttaRifx
  • 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 )
Run Code Online (Sandbox Code Playgroud)

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


你也可以使用Hadley在上面的线程中指出的arrange()函数plyr:

library(plyr)
arrange(dd,desc(z),b)
Run Code Online (Sandbox Code Playgroud)

基准:请注意,由于存在大量冲突,因此我将每个包加载到新的R会话中.特别是加载doBy包导致sort返回"以下对象被屏蔽'x(位置17)':b,x,y,z",并加载sort.data.frame来自Kevin Wright或taRifx包的Deducer包覆盖.

#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
)
Run Code Online (Sandbox Code Playgroud)

中位数时间:

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

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

library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)
Run Code Online (Sandbox Code Playgroud)

中位时间:1,567

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)
Run Code Online (Sandbox Code Playgroud)

中位时间:862

library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)
Run Code Online (Sandbox Code Playgroud)

中位时间:1,694

请注意,doBy需要花费大量时间来加载包.

library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)
Run Code Online (Sandbox Code Playgroud)

无法使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)
Run Code Online (Sandbox Code Playgroud)

由于连接/分离,似乎与微基准不兼容.


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))
Run Code Online (Sandbox Code Playgroud)

微基准图

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


鉴于这些结果和称重简单性与速度,我必须arrangeplyr包装中给予点头.它具有简单的语法,但几乎与基本的R命令一样快速,并且具有复杂的阴谋.通常辉煌的哈德利威克姆工作.我唯一的抱怨是它打破了标准的R术语,其中排序对象被调用sort(object),但我理解为什么Hadley这样做是由于上面链接的问题中讨论的问题.

  • 虽然我承认我发现`microbenchmark`输出很难阅读,但仍然是+1的彻底性 (7认同)
  • 上面的ggplot2微基准测试功能现在可以作为`taRifx :: autoplot.microbenchmark`使用. (3认同)
  • @AME查看样本中`b`的排序方式.默认值是按升序排序,因此您只需将其包装在`desc`中.升入两者:`arrange(dd,z,b)`.在两者中下降:`arrange(dd,desc(z),desc(b))`. (2认同)
  • 按照`?arrange`:"#NOTE:plyr函数不保留row.names".如果想要保留`row.names`,这使得优秀的`arrange()`函数不是最理想的. (2认同)

Mat*_*wle 142

德克的答案很棒.它还强调了用于索引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)]
Run Code Online (Sandbox Code Playgroud)

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

这是一个如何重复变量名称可能会让您陷入麻烦的示例:

让我们从Dirk的答案中改变背景,并说这是一个更大的项目的一部分,其中有很多对象名称,它们很长很有意义; 而不是dd它被称为quarterlyreport.它成为了 :

quarterlyreport[with(quarterlyreport,order(-z,b)),]
Run Code Online (Sandbox Code Playgroud)

好的.没有错.接下来,您的老板要求您在报告中包含上一季度的报告.你仔细检查代码,lastquarterlyreport在各个地方添加一个对象,以某种方式(地球上怎么样?)你最终会得到这个:

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
Run Code Online (Sandbox Code Playgroud)

这不是你的意思,但你没有发现它,因为你做得很快,而且它坐落在一个类似代码的页面上.代码不会失败(没有警告也没有错误),因为R认为这就是你的意思.你希望看到你的报告的人发现它,但也许他们没有.如果您经常使用编程语言,那么这种情况可能都是熟悉的.你会说这是一个"错字".我会解决你对老板说的"拼写错误".

data.table我们关注这样微小的细节.所以我们做了一些简单的事情,以避免两次输入变量名.非常简单.idd自动框架内进行评估.你根本不需要with().

代替

dd[with(dd, order(-z, b)), ]
Run Code Online (Sandbox Code Playgroud)

只是

dd[order(-z, b)]
Run Code Online (Sandbox Code Playgroud)

而不是

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
Run Code Online (Sandbox Code Playgroud)

只是

quarterlyreport[order(-z,b)]
Run Code Online (Sandbox Code Playgroud)

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

  • +1这是一个很好的观点,并且详细了解R的语法经常让我感到烦恼.我有时使用`subset()`只是为了避免在一次调用中重复引用同一个对象. (9认同)
  • 我想你可以在这里添加新的`setorder`函数,因为这个线程是我们发送所有`order`类型的dupes的地方. (5认同)
  • @ naught101 data.table FAQ 1.9是否回答了这个问题? (2认同)

Ben*_*Ben 120

这里有很多优秀的答案,但是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)
Run Code Online (Sandbox Code Playgroud)

对于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
Run Code Online (Sandbox Code Playgroud)

  • 为什么"只"?我发现data.table的`dd [order(-z,b)]`很容易使用和记住. (10认同)
  • 对我而言,它归结为`arrange()`是完全声明的,`dd [order(-z,b)]`不是. (6认同)
  • 当我的列是或类型因素(或类似的东西)时,接受的答案不起作用,我想以降序方式对此因子列进行排序,然后按升序方式对整数列进行排序.但这很好用!谢谢! (2认同)
  • 同意,这两种方法之间并不多,而且`data.table`在许多其他方面也是对`R`的巨大贡献.我想,对于我来说,在这种情况下,可能只有一个较少的括号(或一个较少类型的括号)可以减少认知负荷,只是几乎不可察觉的数量. (2认同)

Aru*_*run 79

R包data.table提供了快速内存有效data.tables排序,具有简单的语法(Matt 在其答案中非常清楚地突出了其中的一部分).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)
Run Code Online (Sandbox Code Playgroud)

基准:

报告的时间来自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
# ------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
  • data.tableDT[order(...)]语法是〜10倍,比最快的其它方法(更快dplyr),同时消耗的存储器中作为相同量dplyr.

  • data.tablesetorder()〜14倍,比最快的其他方法(快dplyr),同时服用刚刚0.4GB额外的内存.dat现在按我们要求的顺序(因为它通过引用更新).

data.table功能:

速度:

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

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

记忆:

  • 大多数情况下,重新排序后我们不需要原始的data.framedata.table.也就是说,我们通常将结果分配回同一个对象,例如:

    DF <- DF[order(...)]
    
    Run Code Online (Sandbox Code Playgroud)

    问题是这需要至少两倍(2x)原始对象的内存.为了节省内存,data.table因此也提供了一个功能setorder().

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

其他特性:

  1. 它支持integer,logical,numeric,character甚至bit64::integer64类型.

    需要注意的是factor,Date,POSIXct等各类都是integer/ numeric类型与下面的附加属性,因此也被支持.

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

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

  • 你评论中的@Arun the Instruments链接已经死了.小心发布更新? (2认同)

Chr*_*ois 69

有了Kevin Wright的这个(非常有用的)功能,发布在R维基的提示部分,这很容易实现.

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
Run Code Online (Sandbox Code Playgroud)

  • 请参阅我的答案,以便对此函数中使用的算法进行基准测试. (2认同)

Geo*_*tas 35

或者您可以使用包doBy

library(doBy)
dd <- orderBy(~-z+b, data=dd)
Run Code Online (Sandbox Code Playgroud)


小智 34

假设您有一个,data.frame A并且您想使用称为x降序的列对其进行排序.调用已排序的data.frame newdata

newdata <- A[order(-A$x),]
Run Code Online (Sandbox Code Playgroud)

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

newdata <- A[order(-A$x, A$y, -A$z),]
Run Code Online (Sandbox Code Playgroud)

在哪里xz哪些列data.frame A.这意味着data.frame Ax降序,y升序和z降序排序.


小智 29

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

  • MJM,谢谢你指出这个包.它非常灵活,因为我的一半工作已经从sql数据库中完成,所以比学习R语言更直观的语法更容易. (7认同)

Ian*_*ows 27

或者,使用Deducer包

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
Run Code Online (Sandbox Code Playgroud)


inf*_*keR 16

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

使用dplyrdata.table

library(dplyr)
library(data.table)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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

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

data.table

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
Run Code Online (Sandbox Code Playgroud)


And*_*rew 15

Dirk的答案很好,但是如果你需要排序来坚持下去,你会想要将排序应用到该数据框的名称上.使用示例代码:

dd <- dd[with(dd, order(-z, b)), ] 
Run Code Online (Sandbox Code Playgroud)


Mar*_*ler 15

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
Run Code Online (Sandbox Code Playgroud)

这个例子工作的唯一原因是因为order是按vector Age,而不是按照名称Age中的列进行排序data frame data.

要查看此内容,请使用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)
Run Code Online (Sandbox Code Playgroud)

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

databyage = my.data[order(age),]
Run Code Online (Sandbox Code Playgroud)

以下行有效,因为order在列age中排序my.data.

databyage = my.data[order(my.data$age),]
Run Code Online (Sandbox Code Playgroud)

我认为这是值得发布的,因为我对这个例子的困惑已经很久了.如果该帖子不适合该帖子,我可以将其删除.

编辑:2014年5月13日

下面是按列分类数据框而不指定列名的通用方法.下面的代码显示了如何从左到右或从右到左排序.如果每列都是数字,则此方法有效.我没有尝试添加字符列.

我在do.call一个或两个月之前在另一个网站上的旧帖子中找到了代码,但只是经过了广泛而艰难的搜索.我不确定我现在可以重新安排那篇文章.目前的主题是订购data.framein 的第一个命中R.所以,我认为我原始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
Run Code Online (Sandbox Code Playgroud)

  • 如果将数据存储在data.table而不是data.frame中,那么该语法会起作用:`require(data.table); my.dt < - data.table(my.data); my.dt [order(age)]`这是有效的,因为列名在[]括号内可用. (4认同)
  • 对“do.call”的支持,这使得对多列数据框进行排序变得很短。只需“do.call(sort, mydf.obj)”即可获得漂亮的级联排序。 (2认同)

小智 10

dplyer中的arrange()是我最喜欢的选项.使用管道操作员,从最不重要到最重要的方面

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))
Run Code Online (Sandbox Code Playgroud)


Ric*_*ick 7

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

 dd <- dd[order(dd$b, decreasing = FALSE),]
Run Code Online (Sandbox Code Playgroud)

现在我们准备做最重要的关键。排序是稳定的,并且最重要的键中的任何关系都已解决。

dd <- dd[order(dd$z, decreasing = TRUE),]
Run Code Online (Sandbox Code Playgroud)

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


Lar*_*off 5

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

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
Run Code Online (Sandbox Code Playgroud)

性能比较:

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
Run Code Online (Sandbox Code Playgroud)

  • 在您的方法最慢时添加性能比较很奇怪...无论如何,在4行`data.frame`上使用基准测试的价值令人怀疑 (4认同)

Sté*_*ent 5

另一种选择,使用该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
Run Code Online (Sandbox Code Playgroud)


AHe*_*gde 5

当我想自动化 n 列的排序过程时,我一直在努力解决上述解决方案,这些列的名称每次都可能不同。我从psych包中找到了一个超级有用的功能,可以以一种简单的方式完成这项工作:

dfOrder(myDf, columnIndices)
Run Code Online (Sandbox Code Playgroud)

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

来自“psych”包的 dfOrder 函数


Dom*_*ois 5

仅出于完整性考虑,由于关于列号排序的讨论很少,因此可以肯定地说,这样做通常是不理想的(因为列的顺序可能会改变,从而为错误铺平了道路),但是在某些特定情况下(例如,当您需要快速完成工作并且没有这样的更改列的风险)时,这可能是最明智的选择,尤其是在处理大量列时。

在这种情况下,请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
##    (...)
Run Code Online (Sandbox Code Playgroud)