sort() はベクトルの値を並べ替える
素のベクトルに対して、sort() はまさに期待どおりのことをします — 値を昇順で返します(元のベクトルは変わりません)。
知っておく価値のあるオプションが 2 つあります。decreasing = TRUE は向きを反転します。そして sort() は既定で NA を黙って 落とします — sort(c(3, NA, 1)) は 1 3 だけを返します。欠損値を並べ替え後も残す必要があるなら、行き先を指定しましょう: sort(x, na.last = TRUE) は並んだ値の後ろに配置して残します。
ここまでは当たり前です。面白いのは、なぜ sort() がデータフレームには 不適切な 道具なのか、という点です。
order() は位置を返す — 発想の転換
sort() は「順に並んだ値は何か?」に答えます。order() は別の問いに答えます。「順番に値を見ていくには どの位置 を訪ねればよいか?」
order(times) は指示書として読みます。最も小さい値は位置 2 にあり、次は位置 4、続いて 1、そして 3。その指示で添字付けすると — times[order(times)] — sort(times) がそのまま再現されます。
なぜそれが重要なのでしょうか。データフレームの行は、一緒に動かなければならない値の チーム だからです。time の列だけを sort() で並べ替えると、1 つの列だけが並べ替わり、チームメイトが置き去りにされます — すべての行がぐちゃぐちゃになります。order() は代わりに行の位置を返し、その位置を括弧の行の枠に入れると 行全体 が動きます。
Ben の 9.8 は Ben の名前を伴って到着します。これがすべての種であり、base R でデータフレームを並べ替えるための 定番 の定型句です: df[order(df$column), ]。(表示される行ラベル 2 4 1 3 は、ついてきた元の行番号です。無害です。)
降順と複数列の並べ替え
数値の降順には列の符号を反転します — -time を昇順に並べることは time を降順に並べることです。また order() は複数の列を取り、先の列が優先され、後の列が同順位を解決します。
2 番目の呼び出しは部署をアルファベット順に並べ、各部署の 中で 給与を高い順に並べます。符号反転の技は数値にしか使えません — 文字列列に対する -df$name はエラーです。テキストの降順には代わりに order(df$name, decreasing = TRUE) を使いましょう(これはすべてのソートキーを一度に反転します)。
rank() は 3 番目の兄弟
ついでに触れると、rank(x) はさらに別の問い — 「各値は何位か?」 — に、何も動かさずに答えます。
sort() は順に並んだ値を、order() は訪ねるべき位置を、rank() は各値のその場での順位を返します。order() と rank() は絶えず混同されます。両者が互いの逆置換であることに注目し、rank() は文字どおり順位が欲しいとき(ランキング表、パーセンタイル)にだけ使いましょう。
dplyr のやり方: arrange()
dplyr の arrange() は order() の一連の手順を 1 つの動詞に包みます。列がソートキーで、desc() が 1 つを反転します(静的な例です。サンドボックスは base R しか実行しません)。
library(dplyr)
runners |> arrange(time)
staff |> arrange(dept, desc(salary))
括弧も $ も符号反転の技も不要で、desc() は文字列列でも動きます。知っておく価値のある挙動の違いが 1 つあります。arrange() は向きに関係なく NA を末尾に置きます。一方 base の order() も既定では na.last = TRUE です。arrange() が filter() などとどう連鎖するかは dplyr 入門 を参照してください。
文字列の並べ替えには鋭い刃がある
テキストを並べ替える際の注意が 2 つあります。第 1 に、テキストとして格納された数字は テキスト として並びます — 文字列の比較は記号ごとに進みます。
"10" が "2" より前に来るのは、比較が最初の記号で決着するからです: "1" < "2"。数値の列が奇妙に並ぶなら、ほぼ確実に文字列として格納されています — まず as.numeric() で変換しましょう(乱雑な CSV インポート の後によく起こることです)。
第 2 に、テキストの順序はシステムの ロケール に依存します — アクセント、大文字小文字、非ラテン文字は、あなたのノート PC と C ロケールのサーバーとで異なる並びになりえます。マシンをまたいで同一でなければならない並べ替え出力は、ロケールを明示的に設定するか、正規化したキーで並べ替えるべきです。
この記事のまとめ
sort(x)はベクトルの値を並べます。decreasing = TRUEで反転し、na.last = TRUEがなければNAは落とされます。order(x)は位置を返し、df[order(df$x), ]がデータフレームを並べ替えるための 定番 の base の定型句です。- 複数列は
order(df$a, -df$b)。降順のための符号反転は数値にしか使えません。 rank()は並べ替えずに順位を返します —order()の代用にはなりません。- dplyr の
arrange(dept, desc(salary))は同じ並べ替えを少ない記号で書けます。 - テキストでは
"10"が"2"より前に来ます — 列の型を確認しましょう。
次は 行をグループ集計にまとめる方法 — table()、tapply()、aggregate()、そして dplyr の group_by() です。
よくある質問
R でデータフレームを列で並べ替えるにはどうすればよいですか?
行の括弧の中で order() を使います: df[order(df$price), ]。order() は並べ替え後の行の位置を返し、それで添字付けするとデータフレーム全体が並べ替わります。ここで sort() は使えません — 1 つのベクトルの値を並べ替えるだけで、他の列とのつながりが失われます。
R の sort() と order() の違いは何ですか?
sort(x) は x の値を並べ替えて返します。order(x) は x を順序どおりに並べるための位置(インデックス)を返します。これは、ある列でデータフレーム全体を並べ替えるのに必要なものです: df[order(df$x), ]。
R で降順に並べ替えるにはどうすればよいですか?
ベクトルなら sort(x, decreasing = TRUE)。データフレームなら df[order(-df$x), ](数値列の符号を反転)か、符号反転が使えない文字列列でも動く df[order(df$x, decreasing = TRUE), ] です。dplyr では arrange(df, desc(x)) です。
R で複数の列を使って並べ替えるにはどうすればよいですか?
すべてを order() に渡します: df[order(df$dept, -df$salary), ] は部署で並べ、各部署の中では給与の降順に並べます。先の引数が主キーで、後の引数が同順位を解決します。dplyr では arrange(df, dept, desc(salary)) です。