Code Fix

中級

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 91 76

論理ベクトルで直接添字指定すると、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")
出力: 25 NA 30

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")
出力: 200 NA 400 NA

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")
出力: NA 22 40

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")
出力: 3 NA 7

在庫が不明(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()」という使い分けを徹底する必要があります。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)