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

Sort (order) data frame rows by multiple columns

提问人:Christopher DuBois 提问时间:8/19/2009 最后编辑:HenrikChristopher DuBois 更新时间:12/8/2021 访问量:1352332

问:

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

评论


答:

89赞 Christopher DuBois 8/19/2009 #1

有了 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
1782赞 Dirk is no longer here 8/19/2009 #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()

评论

17赞 Dirk is no longer here 3/27/2012
应该以相同的方式工作,但你不能使用 .尝试创建一个矩阵,然后用于在两列上对其进行排序。withM <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))MM[order(M[,"a"],-M[,"b"]),]
8赞 Dirk is no longer here 10/21/2012
很简单:,但不能用于基于名称的子集。dd[ order(-dd[,4], dd[,1]), ]with
0赞 HattrickNZ 7/31/2014
为什么无效或'dd[ order(-dd[,4], ]' 基本上是必需的? 如果您只想按 1 列排序还不够?dd[ order(-dd[,4],, ]dd[,1]-dd[,4]
29赞 Richie Cotton 3/24/2015
当您将减号与字符列一起使用时,会发生“一元运算符的无效参数”错误。通过将列包装在 中来解决它,例如。xtfrmdd[ order(-xtfrm(dd[,4]), dd[,1]), ]
38赞 Ian Fellows 8/21/2009 #3

或者,使用包 Deducer

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
46赞 Γιώργος 1/20/2010 #4

或者你可以使用软件包 doBy

library(doBy)
dd <- orderBy(~-z+b, data=dd)
45赞 malecki 3/9/2010 #5

如果 SQL 对你来说是自然而然的,那么包处理会按照 Codd 的意图进行。sqldfORDER BY

评论

8赞 Brandon Bertelsen 7/29/2010
MJM,感谢您指出这个包。它非常灵活,而且因为我的一半工作已经通过从 sql 数据库中提取来完成,所以这比学习 R 的大部分不太直观的语法更容易。
48赞 Khayelihle 1/25/2011 #6

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

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

如果你想要升序,那么用什么都没有替换。你可以有类似的东西"-"

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

其中 和 是 中的某些列。这意味着按降序、升序和降序排序。xzdata.frameAdata.frameAxyz

23赞 Andrew 5/26/2011 #7

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

dd <- dd[with(dd, order(-z, b)), ] 
583赞 Ari B. Friedman 7/29/2011 #8

您的选择

  • orderbase
  • arrangedplyr
  • setorder并从setordervdata.table
  • arrangeplyr
  • sorttaRifx
  • orderBydoBy
  • sortDataDeducer

大多数情况下,您应该使用 or 解决方案,除非具有无依赖关系很重要,在这种情况下,请使用 .dplyrdata.tablebase::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 )

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


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

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

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

#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

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


鉴于这些结果以及称量简单性与速度,我不得不点头安排plyr 包中。它具有简单的语法,但几乎与基本 R 命令一样快速,具有复杂的阴谋诡计。典型的杰出的哈德利·威克姆(Hadley Wickham)作品。我唯一的抱怨是它打破了标准的 R 命名法,其中排序对象被调用,但我理解为什么 Hadley 会这样做,因为上面链接的问题中讨论了问题。sort(object)

评论

5赞 Ari B. Friedman 6/1/2012
上面的 ggplot2 微基准测试函数现在以 .taRifx::autoplot.microbenchmark
0赞 AME 10/12/2013
@AriB.弗里德曼使用“排列”,我们如何按升序排序?我从未见过按升序排序的示例。我尝试了“asc”而不是“desc”,但它不起作用。谢谢
4赞 Ari B. Friedman 10/12/2013
@AME看看样本中的排序方式。默认值是按升序排序,因此您只是不要将其包装在 .在两者中都升序:.两者的降序:.bdescarrange(dd,z,b)arrange(dd,desc(z),desc(b))
4赞 landroni 3/11/2014
根据:“# 注意:plyr 函数不保留 row.names”。如果想要保持,这使得出色的功能次优。?arrangearrange()row.names
0赞 Ari B. Friedman 7/2/2015
如果您改用,其中一些使用可能会更快一些。ordersort.list(x, method=“radix”)
173赞 Matt Dowle 5/26/2012 #9

德克的回答很好。它还突出显示了用于索引 s 和 s 的语法的一个关键区别:data.framedata.table

## 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 回答的上下文,并假设这是一个更大项目的一部分,其中有很多对象名称,它们很长很有意义;而不是它被称为.它变成了:ddquarterlyreport

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

好的,很好。这没有错。接下来,你的老板要求你在报告中包括上一季度的报告。你遍历你的代码,在不同的地方添加一个对象,不知何故(到底是怎么回事?)你最终得到这个:lastquarterlyreport

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

这不是你的意思,但你没有发现它,因为你做得很快,而且它坐落在一个类似代码的页面上。代码不会翻倒(没有警告,也没有错误),因为 R 认为这就是你的意思。你希望阅读你的报告的人能发现它,但也许他们没有。如果您经常使用编程语言,那么这种情况可能非常熟悉。你会说这是一个“错别字”。我会纠正你对老板说的“错别字”。

data.table 中,我们关注的是这样的微小细节。因此,我们做了一些简单的事情来避免输入两次变量名称。很简单的东西。 在已经自动评估的框架内。你根本不需要。iddwith()

而不是

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

只是

dd[order(-z, b)]

而不是

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

只是

quarterlyreport[order(-z,b)]

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

评论

11赞 Josh O'Brien 5/26/2012
+1 这是一个很好的观点,并且涉及 R 语法的一个细节,这经常让我感到恼火。我有时使用 just 来避免在单个调用中重复引用同一对象。subset()
8赞 David Arenburg 1/9/2015
我想您也可以在此处添加新函数,因为此线程是我们发送所有类型复制品的地方。setorderorder
26赞 Mark Miller 9/3/2013 #10

我通过下面的例子了解了这一点,然后让我困惑了很长时间: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

此示例起作用的唯一原因是,它是按 排序的,而不是按 中命名的列排序。ordervector AgeAgedata 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)

上面的行结构不再起作用,因为没有名为 :orderage

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

以下行之所以有效,是因为对 中的列进行排序。orderagemy.data

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

我认为这值得发布,因为我对这个例子感到困惑了这么久。如果这篇文章被认为不适合该线程,我可以将其删除。

编辑:2014 年 5 月 13 日

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

一两个月前,我在另一个网站的旧帖子中找到了代码,但只是经过广泛而困难的搜索。我不确定我现在是否可以重新定位该帖子。当前线程是 in 中排序的第一个命中。所以,我认为我的原始代码的扩展版本可能很有用。do.calldata.frameRdo.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

评论

5赞 Frank 9/3/2013
如果将数据存储在 data.table 而不是 data.frame 中,则该语法确实有效:这之所以有效,是因为列名在 [] 括号内可用。require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]
1赞 A5C1D2H2I1M1N2O1R2T1 2/14/2014
我不认为这里有必要投反对票,但我也不认为这会增加手头的问题,特别是考虑到现有的一组答案,其中一些已经抓住了 s 使用 or 的要求。data.framewith$
2赞 AdamO 5/25/2016
为此,可以缩短对多列数据框进行排序的工作。简单而美丽的级联排序将会进行。do.calldo.call(sort, mydf.obj)
153赞 Ben 2/19/2014 #11

这里有很多很好的答案,但 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

评论

4赞 Saheel Godhane 2/23/2014
当我的列是 or 类型因子(或类似的东西)时,接受的答案不起作用,我想以降序方式对这个因子列进行排序,然后是升序的整数列。但这很好用!谢谢!
14赞 Matt Dowle 3/19/2014
为什么是“只有”?我发现data.table非常易于使用和记忆。dd[order(-z, b)]
3赞 Ben 3/20/2014
同意,这两种方法之间没有太多区别,并且在许多其他方面也做出了巨大贡献。我想对我来说,在这种情况下,少一组括号(或少一种类型的括号)可能会减少几乎无法察觉的认知负荷。data.tableR
12赞 Mullefa 5/29/2015
对我来说,这归结为一个事实,即完全是声明性的,不是。arrange()dd[order(-z, b)]
7赞 Rick 1/15/2015 #12

就像很久以前的机械卡片分拣机一样,首先按最低有效键排序,然后按下一个最重要的键排序,依此类推。无需库,适用于任意数量的键以及升调和降序键的任意组合。

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

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

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

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

103赞 Arun 3/29/2015 #13

R 包通过简单的语法提供了快速节省内存data.tables 排序(Matt 在他的回答中很好地强调了其中的一部分)。从那时起,已经有了相当多的改进和新功能。From 也适用于 data.framesdata.tablesetorder()v1.9.5+setorder()

首先,我们将创建一个足够大的数据集,并对其他答案中提到的不同方法进行基准测试,然后列出 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.table的语法比其他方法中最快的方法快 ~10 倍 (),同时消耗的内存量与 相同。DT[order(...)]dplyrdplyr

  • data.table比其他方法()快~14倍,而只占用0.4GB的额外内存。 现在按我们需要的顺序排列(因为它是通过引用更新的)。setorder()dplyrdat

data.table 功能:

速度:

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

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

记忆:

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

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

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

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

其他功能:

  1. 它支持 、 、 甚至类型。integerlogicalnumericcharacterbit64::integer64

    请注意,、、等。类是带有附加属性的所有 / 类型,因此也受支持。factorDatePOSIXctintegernumeric

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

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

评论

0赞 Julien Navarre 6/30/2015
感谢您对 data.table 的这个非常有启发性的回答。不过,我不明白什么是“峰值内存”以及您是如何计算的。你能解释一下吗?谢谢!
0赞 Arun 6/30/2015
我使用了 Instruments -> 分配并报告了“所有堆和分配 VM”大小。
3赞 MichaelChirico 3/30/2016
@Arun评论中的“工具”链接已失效。想发布更新吗?
0赞 n1k31t4 7/17/2017
@MichaelChirico 以下是有关 Apple 制造的仪器的信息的链接:developer.apple.com/library/content/documentation/...
9赞 Lars Kotthoff 8/7/2015 #14

为了完整起见:您还可以使用包中的函数: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

性能比较:

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赞 MichaelChirico 3/30/2016
奇怪的是,当你的方法最慢时,添加性能比较......无论如何,在 4 行上使用基准测试的价值令人怀疑data.frame
28赞 info_seekeR 2/6/2016 #15

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

使用 和dplyrdata.table

library(dplyr)
library(data.table)

德普莱尔

只需使用 ,这是 的标准评估版本。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
5赞 Stéphane Laurent 5/1/2018 #16

另一种选择,使用包: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
5赞 AHegde 10/25/2018 #17

当我想自动化 n 列的排序过程时,我正在为上述解决方案而苦苦挣扎,这些列的名称每次都可能不同。我从软件包中发现了一个超级有用的功能,可以以一种直接的方式做到这一点:psych

dfOrder(myDf, columnIndices)

其中是一列或多列的索引,按要排序的顺序排列。更多信息请见:columnIndices

“psych”包中的 dfOrder 函数

28赞 Kaden Killpack 10/30/2018 #18

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

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))
12赞 Dominic Comtois 4/11/2019 #19

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

在这种情况下,来救援: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
##    (...)