1435

データ フレームを複数の列で並べ替えたい。たとえば、以下のデータ フレームでは、列 '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
4

19 に答える 19

1743

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()より簡単/より直接的なアクセスのために)。

于 2009-08-18T21:51:22.273 に答える
542

あなたの選択

  • orderからbase
  • arrangeからdplyr
  • setorderそしてsetordervからdata.table
  • arrangeからplyr
  • sortからtaRifx
  • orderByからdoBy
  • sortDataからDeducer

ほとんどの場合、dplyrまたはdata.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 )

あなたがこの関数のオリジナルの作成者の 1 人である場合は、私に連絡してください。パブリック ドメイン性に関する議論はこちら: https://chat.stackoverflow.com/transcript/message/1094290#1094290


上記のスレッドで Hadley が指摘したように、arrange()関数を使用することもできます。plyr

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

ベンチマーク: 多くの競合があったため、各パッケージを新しい R セッションにロードしたことに注意してください。特に、doBy パッケージをロードすると、sort「The following object(s) are masked from 'x (position 17)': b, x, y, z」が返され、Deducer パッケージをロードすると、sort.data.frameKevin Wright または 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)

アタッチ/デタッチのため、マイクロベンチマークと互換性がないようです。


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

マイクロベンチマーク プロット

(線は下位四分位数から上位四分位数まで伸びており、ドットは中央値です)


arrangeこれらの結果と、単純さと速度の比較を考えると、plyrパッケージにうなずく必要があります。これは単純な構文を持ちますが、複雑な操作を伴うベース R コマンドとほぼ同じくらい高速です。典型的に素晴らしいハドリー・ウィッカムの作品。私の唯一の不満は、オブジェクトの並べ替えが によって呼び出される標準の R 命名法を破ることですが、sort(object)上記のリンクされた質問で説明されている問題のために、Hadley がそのようにした理由を理解しています。

于 2011-07-29T10:48:00.077 に答える
166

ダークの答えは素晴らしいです。data.frameまた、 s と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)]

2 つの呼び出しの違いはわずかですが、重要な結果をもたらす可能性があります。特に、製品コードを作成したり、調査の正確性に関心がある場合は、変数名を不必要に繰り返すことを避けるのが最善です。data.table これを行うのに役立ちます。

以下は、変数名の繰り返しによって問題が発生する可能性がある例です。

コンテキストを Dirk の回答から変更してみましょう。これは、オブジェクト名が多く、長くて意味のある、より大きなプロジェクトの一部であるとしましょう。ddと呼ばれる代わりにquarterlyreport。あれは。。。になる :

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

いいよ。それは何も悪いことではありません。次に上司から、前四半期のレポートをレポートに含めるように求められました。コードを調べて、さまざまな場所にオブジェクトlastquarterlyreportを追加すると、どういうわけか(一体どうやって?)、次のようになります:

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

それはあなたが意図したものではありませんが、あなたはそれをすばやく実行し、同様のコードのページに囲まれているため、それを見つけられませんでした. R はそれが意図したとおりであると判断するため、コードはフォールオーバーしません (警告もエラーもありません)。レポートを読んだ人がそれを見つけてくれることを願っていますが、そうではないかもしれません。プログラミング言語を頻繁に使用する場合、この状況はおなじみかもしれません。それはあなたが言う「タイプミス」でした。あなたが上司に言う「タイプミス」を直します。

ではdata.table、このような細かい部分に気を配っています。そのため、変数名を 2 回入力するのを避けるために簡単なことをしました。とてもシンプルなもの。iのフレーム内ddで自動的に評価されます。まったく必要ありませんwith()

それ以外の

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

それはただ

dd[order(-z, b)]

そして代わりに

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

それはただ

quarterlyreport[order(-z,b)]

それは非常に小さな違いですが、いつかあなたの首を救うかもしれません. この質問に対するさまざまな答えを比較検討するときは、決定の基準の 1 つとして変数名の繰り返しを数えることを検討してください。かなりの数の繰り返しがある回答もあれば、まったくない回答もあります。

于 2012-05-25T16:25:56.303 に答える
146

ここには多くの優れた回答がありますが、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
于 2014-02-18T21:29:25.363 に答える
97

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(...)]. _ _ _ dplyr_ dplyr_

  • data.tablesetorder()は、他の最速の方法 ( ) よりも最大 14 倍高速でしたが、わずか0.4GBの余分なメモリしか必要としませんでした。必要な順序になりました (参照によって更新されるため)。dplyrdat

data.table の機能:

スピード:

  • data.tableの順序付けは、基数順序付けを実装しているため、非常に高速です。

  • 構文は、 data.tableの高速順序付けもDT[order(...)]使用するように内部的に最適化されています。使い慣れたベース R 構文を使い続けることができますが、プロセスを高速化できます (そしてメモリの使用量が少なくなります)。

メモリー:

  • ほとんどの場合、並べ替え後に元のdata.frameまたはdata.tableは必要ありません。つまり、通常は結果を同じオブジェクトに割り当てます。次に例を示します。

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

    問題は、元のオブジェクトの少なくとも 2 倍 (2x) のメモリが必要になることです。したがって、メモリ効率を高めるために、data.tableには関数も用意されていますsetorder()

    setorder()追加のコピーを作成せずに、data.tables by reference ( in-place ) を並べ替えます。1 つの列のサイズに等しい余分なメモリのみを使用します。

その他の機能:

  1. integerlogicalnumericcharacterさらにはタイプをサポートしbit64::integer64ます。

    、などのクラスはすべて/タイプの下に追加の属性があるため、同様にサポートされていることfactorに注意してください。DatePOSIXctintegernumeric

  2. ベース R では-、文字ベクトルを使用して、その列で降順で並べ替えることはできません。代わりに を使用する必要があります-xtfrm(.)

    ただし、data.tableでは、たとえばdat[order(-x)]orを実行できsetorder(dat, -x)ます。

于 2015-03-29T15:52:00.073 に答える
82

R wiki のヒント セクションに投稿されたKevin Wright によるこの (非常に役立つ) 関数を使用すると、これを簡単に実現できます。

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
于 2009-08-18T21:37:22.160 に答える
45

があり、降順data.frame Aという列を使用して並べ替えたいとします。xソートされたものを呼び出すdata.frame newdata

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

昇順が必要な場合は"-"、何も置き換えません。あなたは次のようなものを持つことができます

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

ここでx、 とzは のいくつかの列ですdata.frame A。これはdata.frame Ax降順、y昇順、降順で並べ替えることを意味しますz

于 2011-01-25T13:10:21.227 に答える
43

または、パッケージdoByを使用できます

library(doBy)
dd <- orderBy(~-z+b, data=dd)
于 2010-01-19T20:44:38.270 に答える
41

SQL が自然に思い浮かぶ場合、sqldfパッケージはORDER BYCodd が意図したとおりに処理します。

于 2010-03-08T23:30:37.280 に答える
35

または、パッケージ Deducer を使用して

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
于 2009-08-20T19:43:30.170 に答える
24

プログラムでソートする方法についてOPに追加されたコメントに応えて:

dplyrと_data.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
于 2016-02-05T21:11:52.757 に答える
22

次の例で学びまし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 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)

という名前のベクトルがないため、上記の行構造はorder機能しなくなりましたage

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

次の行は、 の列でorderソートされるため機能します。agemy.data

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

この例で長い間混乱していたことを考えると、これは投稿する価値があると思いました。この投稿がスレッドにふさわしくないと判断された場合は、削除できます。

編集: 2014 年 5 月 13 日

以下は、列名を指定せずにすべての列でデータ フレームを並べ替える一般的な方法です。次のコードは、左から右または右から左に並べ替える方法を示しています。これは、すべての列が数値の場合に機能します。文字列を追加して試したことはありません。

do.call1、2 か月前に、別のサイトの古い投稿でコードを見つけましたが、広範かつ困難な検索を行った後で初めてのことでした。そのポストを今すぐ移転できるかどうかはわかりません。現在のスレッドは、 で a を注文するための最初のヒットdata.frameです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
于 2013-09-02T19:28:56.113 に答える
21

Dirkの答えは良いですが、並べ替えを永続化する必要がある場合は、そのデータフレームの名前に並べ替えを適用する必要があります。サンプルコードの使用:

dd <- dd[with(dd, order(-z, b)), ] 
于 2011-05-26T15:08:39.597 に答える
8

完全を期すために、パッケージの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
于 2015-08-07T04:03:34.287 に答える
7

昔の機械式カード ソーターと同じように、最初に重要度の低いキーで並べ替え、次に重要度の高いキーで並べ替えます。ライブラリは不要で、任意の数のキーと、昇順キーと降順キーの任意の組み合わせで動作します。

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

これで、最も重要なキーを実行する準備が整いました。並べ替えは安定しており、最も重要なキーの関係は既に解決されています。

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

これは最速ではないかもしれませんが、確かにシンプルで信頼性があります

于 2015-01-15T04:28:25.050 に答える