はじめに
Rにおいては、NAが関わる演算は基本的にNAを返す。例えば、以下の式をRで計算すると、いずれもNAが返される。
NA + 5 # [1] NA 2 * NA # [1] NA 3 ^ NA # [1] NA
しかし、NAが関わる演算であってもNA以外の値が返されることがある。例えば、NAの0乗は1を返す。
NA ^ 0 # [1] 1
同じNAが関わる演算なのに、NAが返されるものと、それ以外の値が返されるものがあるというのはどういう道理なのだろうか。
答えを先に言えば、以下のような単純な仕組みになっている。
- NAがある位置に他のどんな値が入ったとしても返される値が同じになる場合は、その値が返される。
- それ以外の場合は、NAが返される。
後で紹介する「NAの0乗」や「FALSEとNAの論理積」などは上記の1番目に対応する例で、それぞれ1, FALSEが返される。これに対して、「NA + 5」や「6 * NA」などは上記の2番目に対応する例で、いずれもNAが返る。
NAとは
なお、RでのNAとは、欠損値を示す特別な定数である。NAは“Not Available”(入手不可能)の頭文字を合わせたものである。
実際、Rのドキュメンテーションにおいては、“NA is a logical constant of length 1 which contains a missing value indicator.”(引用者訳:NAとは、長さ1の論理定数であり、欠損値を指し示すものを含む。) ((R Core Team. (2016). R: 'Not Available' / Missing Values. Retrieved October 04, 2016, from http://stat.ethz.ch/R-manual/R-devel/library/base/html/NA.html [Package base version 3.3.0].)) とされている。
さて、以下、具体的にNAが関わる演算について見ていこう。
NAが関わる加減乗除・累乗
まずは簡単な事例として、NAに5を足す計算、すなわち NA + 5 について考えてみよう。これをRで計算すると、NAが返される。つまり、データに欠損があって値がよく分からないものに対して、5という数を加えたとしても、結局は分からないままだということを意味している。
NA + 5 の例と同様に、NAが関わる加減乗除は、すべてNAを返す。RでのNAが関わる加減乗除の例を以下に示す。
NA + 5 # [1] NA 7 + NA # [1] NA 10 - NA # [1] NA NA -12 # [1] NA NA * 3 # [1] NA 6 * NA # [1] NA NA / 9 # [1] NA 21 / NA # [1] NA NA + 0 # [1] NA 0 + NA # [1] NA NA - 0 # [1] NA 0 - NA # [1] NA NA * 0 # [1] NA 0 * NA # [1] NA NA / 0 # [1] NA 0 / NA # [1] NA
累乗に関しても、基本的にはNAを返す。
NA ^ 3 # [1] NA 5 ^ NA # [1] NA 0 ^ NA # [1] NA
ただし、NAの0乗は1を返す。
NA ^ 0 # [1] 1
なぜNAの0乗の答えとして、NAが返らずに、1が返るのだろうか。このことは、反実仮想的な観点から考えると分かりやすい。つまり、もしここのNAが欠損していなかったらどうなるかと考えてみるのだ。
NAの位置に42が入っていたらどうなるだろうか。42の0乗だから、これは1になる。また、NAの位置に29.31が入っていたらどうなるだろうか。29.31の0乗だから、これまた1になる。
両方とも1になったのは偶然ではない。数学の授業で習ったことがあるかもしれないが、どんな数でも0乗すれば1になるのだ ((厳密に言うと、0の0乗についてはそもそも定義されないこともあるので、数学一般の話として「どんな数でも」と述べるのは言い過ぎになる。ただ、Rでは0の0乗が1と定義されているので、Rの中では、どんな数でも0乗すれば1になる。)) 。
だから、たとえ欠損が発生していなかった場合にNAの位置にどんな数が入るか分からなかったとしても、それを0乗したものの答えが1になるということは分かるのだ。
このことによって、RはNAの0乗の答えとして1を返すことになる。
ところで、NAに0を乗じたもの、すなわち NA * 0 はNAが返る。なぜここで、0が返らないのだろうか。どんな実数であったとしても0を乗じれば必ず0になるのだから、NAの0乗が1を返したように、NAに0を乗じたものも1を返して良さそうなものだ。なぜそうならないのだろうか。
実は、Rでは無限大に0を乗じたもの、すなわち Inf * 0 を計算すると、NaN(非数)が返ることになっている。よって、NA * 0 の NA の位置に Inf が入っていたとしたら、答えは NaN になるのだ。これに対して、NA * 0 の NA の位置に普通の数(42, -3.9, 324,513.79など)が入っていたら答えは0になる。よって、NAの位置に入るものによって、答えが変わることになる。
だから、NAの位置に入る値が分からない以上、結果は分からないままということになるので、NA * 0 はNAが返されるのである。
NAが関わる論理演算
論理演算でも同様のことが起きる。つまり、NAがある位置に他のどんな値が入ったとしても返される値が同じになる場合は、その値が返されるのだ。
Rでは、&で論理積(かつ)を示し、| で論理和(または)を示す。ここで、FALSEとNAの論理積、すなわち FALSE & NA はFALSEを返す。また、TRUEとNAの論理和である TRUE | NA はTRUEを返す。なぜこうなるのだろうか。
FALSEとNAの論理積について考えよう。FALSE & NA において、NAの位置に他の値が入ったときのことを考えてみよう。論理演算なので、他の値の候補としては、TRUE と FALSEしかない。
NAの位置にTRUEが入ったとしよう。このとき、FALSE & TRUE という式になる。TRUEとFALSEの論理積なので、これはFALSEになる。
また、NAの位置にFALSEが入ったとしよう。このとき、FALSE & FALSE という式になる。FALSEとFALSEの論理積なので、これまたFALSEになる。
よって、どんな値が入ったとしても、必ずFALSEになるので、FALSE & NA はFALSEとなるのだ。
これが、FALSE & NA でなく、TRUE & NA ならば状況は変わってくる。NAの位置にTRUEが入ったとしたらTRUEになり、FALSEが入ったとしたらFALSEとなるので、結果としてどちらになるかが分からない。だから、結果として、TRUE & NA は NAが返される。
実際にRで論理演算を実施する例を以下に掲げる。
TRUE & NA # [1] NA FALSE & NA # [1] FALSE NA & NA # [1] NA TRUE | NA # [1] TRUE FALSE | NA # [1] NA NA | NA # [1] NA
まとめ
今まで見てきたように、RのNAに関する演算では、以下のような仕組みが成り立っている。
- NAがある位置に他のどんな値が入ったとしても返される値が同じになる場合は、その値が返される。
- それ以外の場合は、NAが返される。
1番目に当てはまる例としては、「NAの0乗」、「FALSEとNAの論理積」、「TRUEとNAの論理和」がある。
実際のデータ分析では、直接NAに対して演算を行うことはあまりないだろう。ただ、変数の中にNAが入っていて、自分が意図していないところでNAに関する演算が行われている可能性はある。数を0乗することはさほどないだろうが、論理積や論理和をとることはそれなりにあると思うので、そうしたときに混乱しないように注意したいものだ。