table用法 - r選取資料




如何按列排序數據框? (10)

我想通過多列對數據框進行排序。 例如,在下面的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

您的選擇

  • base order
  • 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..com/transcript/message/1094290#1094290 : http://chat..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會這樣做,因為上面鏈接問題中討論的問題。


Dirk的答案很好,但如果你需要這種排序來堅持下去,你會希望將排序應用到該數據框的名稱上。 使用示例代碼:

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

作為對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

假設你有一個data.frame A並且你想使用名為x降序的列對它進行排序。 調用排序後的data.frame newdata

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

如果你想要升序,那麼用"-"替換為空。 你可以有類似的東西

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

其中xzdata.frame A中的一些列。 這意味著按x降序, y升序和z降序對data.frame A進行排序。


就像很久以前的機械卡片分揀機,首先按最不重要的鑰匙排序,然後排在下一個最重要的鑰匙上,等等。不需要圖書館,可以使用任意數量的按鍵以及任意組合的上升和下降按鍵。

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

現在我們準備做最重要的關鍵。 排序是穩定的,最重要的關鍵中的任何關係都已經解決。

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

這可能不是最快的,但它確實簡單可靠


德克的回答很好。 它還強調了用於索引data.frame s和data.table s的語法中的一個關鍵區別:

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

好的。 沒有錯。 接下來你的老闆會要求你在報告中包含上個季度的報告。 你通過你的代碼,在不同的地方添加一個對象,並以某種方式(最終如何在這個地方?)最終得到這個結果:

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

這不是你的意思,但你沒有發現它,因為你做得很快,它是在一個類似的代碼頁面上。 代碼不會翻倒(沒有警告和錯誤),因為R認為它是你的意思。 你希望看到你的報告的人看到它,但也許他們沒有。 如果你使用編程語言很多,那麼這種情況可能會讓人很熟悉。 這是一個你會說的“打字錯誤”。 我會解決你對老闆說的“打字錯誤”。

data.table我們關注這樣的細節。 所以我們做了一些簡單的事情來避免兩次輸入變量名。 一些非常簡單的東西。 i已經自動地在dd幀內dd進行了評估。 with()完全不需要。

代替

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

只是

dd[order(-z, b)]

而不是

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

只是

quarterlyreport[order(-z,b)]

這是一個非常小的差異,但它可能只會挽救你的脖子有一天。 在權衡這個問題的不同答案時,考慮將變量名稱的重複計數作為您決定的標準之一。 有些答案有不少重複,其他答案沒有。


我用下面的例子了解了一下,然後困惑了很長時間:

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

或者你可以使用包doBy

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


為了完整起見:您還可以使用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




r-faq