r读取数据框 - r选取数据




如何按列排序数据框? (10)

您的选择

  • base
  • dplyr arrange
  • 来自data.table setorderdata.table
  • plyr arrange
  • taRifx sort
  • doBy
  • 来自Deducer

大多数情况下,您应该使用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 : http://chat.stackoverflow.com/transcript/message/1094290#1094290

您也可以使用Hadley在上述线程中指出的plyrarrange()函数:

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

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

由于附着/分离,似乎与microbenchmark不兼容。

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命令与它们的复杂旋转几乎一样快。 典型的辉煌哈德利韦克汉姆的工作。 我唯一抱怨的是,它打破了标准R命名法,其中按sort(object)排序对象进行调用,但是我明白为什么Hadley会这样做,因为上面链接问题中讨论的问题。

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

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

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

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

作为对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 : 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

如果SQL自然适合你,sqldf会像Codd预期的那样处理ORDER BY。


就像很久以前的机械卡片分拣机,首先按最不重要的钥匙排序,然后排在下一个最重要的钥匙上,等等。不需要图书馆,可以使用任意数量的钥匙以及任何升降键组合。

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

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

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

这可能不是最快的,但它确实简单可靠


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


我用下面的例子了解了一下,然后困惑了很长时间:

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

以下行my.data因为ordermy.data的列agemy.data

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

或者,使用包Deducer

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





r-faq