行の絞り込み: 論理マスク
R でデータフレームを絞り込むには、括弧の 行の位置 に条件を書きます: df[condition, ]。条件は行ごとに 1 つの TRUE/FALSE からなるベクトルに評価され、R は TRUE の行を残します。
scores[scores$score > 80, ] を内側から読みましょう。scores$score > 80 は TRUE FALSE TRUE TRUE FALSE を生み、括弧は 1 行目、3 行目、4 行目を残します。末尾のカンマは省略可能ではありません。 データフレームに対する括弧は [行, 列] を取り、列の枠を空にすることは「すべての列」を意味します。カンマを忘れると、行ではなく列を添字付けすることになります — R で最もよくある初心者のエラーの 1 つです。
表示される行番号が 1 2 3 ではなく 1 3 4 であることに注目してください。絞り込みは元の行ラベルを保持します。無害ですが、人を驚かせます。
複数条件: & と |(&& ではない)
条件は &(AND)と |(OR)で組み合わせます。各条件はそれぞれ完全な比較を持ちます。
罠があります。R には && と || もありますが、ここでは & や | と 交換できません。二重の形は単一の値に対して働きます(if の条件のために存在します)。列全体を与えると、現代の R(4.3 以降)は 'length = 5' in coercion to 'logical(1)' のようなエラーで停止し、古い R は黙って最初の行だけを比較していました — 間違いなくこちらの方が悪質です。括弧の中では常に単独の & と | を使いましょう。演算子のドキュメント がこの区別を詳しく扱っています。
%in%: 値の集合との照合
ある列が複数の値のいずれかに一致すべきときは、== を | でつなぐのではなく %in% を使いましょう。
x %in% set は x が set の値のいずれかである位置で TRUE を返します。status == "pending" | status == "shipped" より読みやすく、値がいくつあってもスケールし、否定もきれいに書けます: !(orders$status %in% c("refunded"))。
列の選択
括弧の列の枠は名前または位置を受け取ります。
注意点が 2 つ。名前による選択は列の並べ替えに耐えますが、位置による選択(scores[, c(1, 3)])は誰かが列を挿入した日に壊れます。また、単一 の列を要求するとデータフレームではなく素のベクトルが返ります — 2 つ目の print() が表の枠なしに 91 88 を表示するのはそのためです。データフレームの形を保ちたいときは drop = FALSE を加えます: scores[, "score", drop = FALSE]。
subset(): base の親切な 1 行
base R には、行と列を 1 回の読みやすい呼び出しで扱うラッパーが同梱されています — $ も、カンマの管理も不要です。
subset() の中では裸の列名を書きます(scores$score ではなく score)。データフレームを背景にそれらを評価するのです。これは 非標準評価 と呼ばれ、文書化された注意事項が伴います。実行時に名前を解決する方法が、自作の関数の中では不適切に振る舞います(関数内の score という変数が、score という列に隠されてしまうことがあります)。?subset にそのまま書かれている経験則はこうです。対話的には素晴らしいが、プログラミングでは避け、そこでは括弧による添字付けを使う。
NA の罠
NA との比較は FALSE ではなく NA を生み、括弧による絞り込みは NA のマスクの行を NA だらけの行として残します。
最初の結果には NA だらけのゴミ行が含まれます。2 行目の条件が TRUE でも FALSE でもなかったからです。対処は !is.na() を明示的に要求することです。subset() と dplyr の filter() はどちらも条件が NA の行を黙って落とします — 便利ですが、それが起きていることを知っておきましょう。NA がなぜこのように広がるのかは 欠損値のドキュメント で扱っています。
dplyr のやり方: filter() と select()
dplyr パッケージは仕事を 2 つの動詞に分けます — 行には filter()、列には select() — 裸の列名を使い、df$ の繰り返しがありません(静的な例です。サンドボックスは base R しか実行しません)。
library(dplyr)
scores |> filter(score > 80)
scores |> filter(score > 80, team == "red") # comma = AND
scores |> filter(status %in% c("pending", "shipped"))
scores |> select(name, score)
scores |> filter(team == "red") |> select(name, score)
filter() は条件が NA の行を自動的に落とし、常にデータフレームを返します(裸のベクトルになることはありません)。これで上記の base の落とし穴が 2 つとも消えます。代償はパッケージへの依存と、subset() と同じ非標準評価の注意事項です — 動詞の全体像は dplyr 入門 を参照してください。
この記事のまとめ
df[condition, ]が基本の定型句です — そしてカンマは必須です。- 条件は単独の
&と|で組み合わせます。&&はベクトルに対してエラーになります。 - 値の集合との照合には、
==の連鎖より%in%が優れています。 - 列は名前で選びましょう。単一の列は
drop = FALSEを付けない限りベクトルに落ちることを忘れずに。 subset()は対話的に心地よい 1 行、括弧はプログラム向きです。NAとの比較は括弧でゴースト行を生みます —!is.na()で守りましょう。
次は 列の追加と変換 — df$new <- ...、ifelse()、そして dplyr の mutate() です。
よくある質問
R でデータフレームの行を絞り込むにはどうすればよいですか?
括弧の行の位置に論理条件を書きます: df[df$score > 80, ]。条件は TRUE/FALSE のベクトルを生み、R は TRUE の行を残します。カンマが重要です — 行のフィルタと(空の)列のフィルタを区切ります。subset(df, score > 80) は同じことをより少ない入力で行います。
R で複数条件による絞り込みはどうすればよいですか?
条件を &(AND)と |(OR)で組み合わせます: df[df$score > 80 & df$team == "red", ]。&& ではなく単独の & を使ってください。二重の形は単一の値にのみ働き、現代の R ではベクトルに対してエラーになります。
R の subset() と括弧による絞り込みの違いは何ですか?
残る行は同じですが、違いが 2 つあります。subset() は条件が NA になる行を黙って落とします(括弧はそれを NA で埋まった行として残します)。また subset() は非標準評価を使い、裸の列名を書けます。対話的には便利ですが、自作の関数の中では信頼できません。
ある列が値のリストのいずれかに一致する行を絞り込むにはどうすればよいですか?
%in% を使います: df[df$team %in% c("red", "blue"), ] は team が列挙した値のいずれかである行を残します。| でつないだ == の連鎖を置き換えられますし、== と違って NA を返すことがありません。