which() の戻り値と論理ベクトルによる添字指定を混同するとずれる
which(条件)は条件を満たす要素の「位置(添字番号)」を返しますが、条件そのもの(論理ベクトル)を直接添字として使うのとは意味が違います。which()の結果をさらに論理ベクトルとして使うと、位置の数値がTRUE/FALSEとして解釈され、意図と違う要素が選ばれます。
なぜエラーが出ないのか
出力: NA 91 76
(エラーなし)- Rは何も報告しません。文法としても実行としても正しいコードだからです
NA 91 76- 実際の出力 — 期待した結果と食い違っている箇所
このエラーが出る典型パターン
パターン1
1 scores <- c(45, NA, 91, 33, 76) 2 passed <- scores[scores >= 60 ] ^ 3 cat(passed, "\n")
論理ベクトルで直接添字指定すると、NAだった位置もNAのまま結果に残ります。which()を使うとNAの位置は結果から除外されます。
直し方: scores >= 60 を which(scores >= 60) にします。
パターン2
1 temps <- c(18, 25, NA, 30, 12) 2 hot <- temps[temps > 20 ] ^ 3 cat(hot, "\n")
temps > 20はNAの位置でもNAを返すため、そのまま添字にするとhotの中にNAが紛れ込みます。
直し方: temps > 20 を which(temps > 20) にします。
パターン3
1 amounts <- c(200, NA, 50, 400, NA) 2 big <- amounts[amounts >= 100 ] ^ 3 cat(big, "\n")
NAを含む条件を論理添字にそのまま使うと、判定不能だった要素までNAとして結果に残ってしまいます。
直し方: amounts >= 100 を which(amounts >= 100) にします。
パターン4
1 ages <- c(15, NA, 22, 40, 8) 2 adults <- ages[ages >= 18 ] ^ 3 cat(adults, "\n")
which(ages >= 18)はNAの位置を候補から除外しますが、ages >= 18を直接使うとNAがそのまま残ります。
直し方: ages >= 18 を which(ages >= 18) にします。
パターン5
1 stock <- c(3, 0, NA, 7, 0) 2 available <- stock[stock > 0 ] ^ 3 cat(available, "\n")
在庫が不明(NA)な行まで論理添字ではそのまま残ってしまうため、which()で位置を確定させてから添字にする必要があります。
直し方: stock > 0 を which(stock > 0) にします。
よくある誤解
「which(条件)もx[条件]も同じ要素を選んでくれるはず」という思い込みは誤りです。which()は位置の番号を返す関数で、その番号をもう一度論理的な添字指定として使うと、数値が0でなければTRUE扱いになるため、ほとんどの要素が選ばれてしまいます。
実務での勘所
この混同が典型的に表れるのは、「条件を満たす個数を数えたい」場面です。sum(x > 3)は論理ベクトルのTRUEを1、FALSEを0として合計するため、条件を満たす要素の個数が正しく得られる、Rでよく使われる定石です。ここでうっかりwhich()を挟んでsum(which(x > 3))と書いてしまうと、条件を満たす位置の番号そのものを合計した、意味の無い数値が返ってきます。「個数を数えたいなら論理ベクトルのまま、位置が欲しいときだけwhich()」という使い分けを徹底する必要があります。