如何按多个列对数据框进行排序


1316

我想按多个列对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

Answers:


1624

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


@Dirk Eddelbuettel是否有类似的简单矩阵方法?
2012年

14
应该以相同的方式工作,但是您不能使用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"]),]在两列上对其进行排序。
德克·埃德尔布特尔

4
足够简单:dd[ order(-dd[,4], dd[,1]), ],但不能with用于基于名称的子设置。
德克·埃德尔布特尔

18
运行第二个示例时,出现“一元运算符的无效参数”错误。
Nailgun

21
当在字符列中使用减号时,将发生“一元运算符的无效参数”错误。xtfrm例如,将列包装在其中即可解决该问题dd[ order(-xtfrm(dd[,4]), dd[,1]), ]
Richie Cotton

476

您的选择

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

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


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

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

基准测试:请注意,由于存在很多冲突,因此我在新的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
)

中位数:

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)

无法进行演绎器加载。需要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))

微基准图

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


考虑到这些结果并权衡简单性与速度,我必须arrangeplyr包装中表示赞同。它具有简单的语法,但几乎与基本R命令一样复杂,具有复杂的机加工。通常是出色的哈德利·威克姆(Hadley Wickham)的作品。我唯一的困扰是它打破了标准的R命名法,即通过调用排序对象sort(object),但是我理解为什么Hadley会因为上述问题中讨论的问题而采用这种方式。


3
上面的ggplot2微基准功能现在可以作为使用taRifx::autoplot.microbenchmark
阿里·弗里德曼

@ AriB.Friedman y轴间隔是多少/比例是多少?
naught101

@ naught101 y轴从0开始。标度应为微秒。
阿里·弗里德曼

2
@AME看看b示例中的排序方式。默认值是按升序排序,因此您不必将其包装在中desc。两者都升序:arrange(dd,z,b)。两者同时下降:arrange(dd,desc(z),desc(b))
阿里·弗里德曼

2
按照?arrange:“#注意:plyr函数不保留row.names”。arrange()如果要保留,则使出色的功能不理想row.names
landroni 2014年

148

德克的答案很好。它还强调了索引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)]

这是一个很小的差异,但是有一天可能会节省您的脖子。在权衡此问题的不同答案时,请考虑将变量名的重复数作为决定的标准之一。有些答案有很多重复,有些则没有。


9
+1这是一个很好的观点,并详细介绍了经常激怒我的R语法。有时我subset()只是为了避免必须在单个调用中重复引用同一对象。
乔什·奥布莱恩

2
@ naught101 data.table常见问题解答1.9回答了这个问题吗?
马特·道尔

5
我猜您也可以在setorder此处添加新功能,因为此线程是我们发送所有order类型重复项的地方。
David Arenburg

125

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

2
当我的列是type或type factor(或类似的东西)并且我想对此因子列按降序排序,然后对我的整数列进行升序排序时,可接受的答案不起作用。但这很好用!谢谢!
Saheel Godhane 2014年

10
为什么是“仅”?我发现data.table dd[order(-z, b)]非常易于使用和记住。
Matt Dowle 2014年

2
同意,这两种方法之间没有太多区别,并且在许多其他方面也data.table做出了巨大贡献R。我想对我来说,可能是在这种情况下减少了一组括号(或一种类型的括号)将认知负荷降低了几乎无法感知的程度。
2014年

7
对我来说,它可以归结arrange()为完全声明性的事实,dd[order(-z, b)]而不是声明性事实。
Mullefa

83

R包data.table通过简单的语法提供data.tables的快速内存有效排序(Matt 在回答中很好地强调了其中的一部分)。从那时起,已经进行了很多改进,并增加了新功能。从,还可以与data.frames一起使用setorder()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.tableDT[order(...)]语法比其他方法中最快的()快约10倍dplyr,同时消耗的内存量与相同dplyr

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

data.table功能:

速度:

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

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

记忆:

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

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

    问题是这至少需要原始对象的两倍(2倍)的内存。为了提高内存效率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的非常有启发性的答案。虽然,我不知道什么是“峰值内存”以及如何计算。你能解释一下吗?谢谢 !
朱利安·纳瓦拉

我使用仪器 ->分配,并报告了“所有堆和分配VM”的大小。
阿伦(Arun)2015年

2
您评论中的@Arun Instruments链接已死。想要发布更新吗?
MichaelChirico

@MichaelChirico这是苹果公司生产的乐器的信息链接:developer.apple.com/library/content/documentation/…–
n1k31t4



39

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

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

如果要升序,则"-"什么也不要替换。你可以有类似的东西

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

xz中的一些列data.frame A。这意味着data.frame Ax降序,y升序和z降序排序。


32

如果您很自然地使用SQL,请按照Codd的意图sqldf处理包ORDER BY


7
MJM,感谢您指出此包装。它非常灵活,并且因为我的一半工作已经通过从sql数据库中提取完成,所以比学习R少得多而不是直观语法要容易得多。
布兰登·贝特尔森

31

或者,使用软件包Deducer

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

19

针对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

18

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,而不是由一个名为列Agedata 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)

上面的线结构order不再起作用,因为没有名为的向量age

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

以下行之所以有效,是因为order对的列age进行了排序my.data

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

考虑到我这么长时间以来一直对这个例子感到困惑,所以我认为这值得一提。如果该帖子不适合该主题,我可以将其删除。

编辑: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

4
如果将数据存储在data.table中而不是data.frame中,则该语法确实起作用:require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]之所以有效,是因为在[]括号内提供了列名。
弗兰克(Frank)

我认为在这里无需投票,但我也不认为这会给当前的问题增加太多,尤其是考虑到现有的答案集,其中一些答案已经data.frame使用with或使用捕获了需求$
A5C1D2H2I1M1N2O1R2T1

1
给予好评对于do.call这使得排序多列的数据帧的短的工作。简单do.call(sort, mydf.obj)而美丽的级联排序将是有的。
AdamO '16

17

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

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


7

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

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

6

为了完整起见:您还可以使用包中的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
奇怪的是,当您的方法最慢时添加性能比较...无论如何,在4行上使用基准测试的价值令人怀疑data.frame
MichaelChirico

5

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

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

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

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

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



4

当我想自动执行n列的排序过程时,我在上述解决方案上苦苦挣扎,因为n列的列名每次都可能不同。我从psych包中发现了一个超级有用的功能,可以通过简单的方式执行此操作:

dfOrder(myDf, columnIndices)

columnIndices一列或多列的索引在哪里,按您要对其排序的顺序。此处的更多信息:

来自“ psych”包的dfOrder函数

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.