NA,NaN,NULL,Inf
NULL (何も無い) ,Na (欠損値) ,NaN (非数) ,Inf (無限大) についてのネタを集めました.
NULL (何も無い) ,Na (欠損値) ,NaN (非数) ,Inf (無限大) については,これらの値にどのような演算を施しても,大抵はそのままの値 ( NA や NAN ) が返ってくる.すなわち,原則として NaN にどのような演算を施しても結果は NaN になる.よって,比較演算子 == すら使えないことになる.
x <- c(1.0, NA, 3.0, 4.0, 5.0) # NA がある要素はどれかを調べようとしているのだが ... x == NA # NA に対する演算は全て NA になってしまう [1] NA NA NA NA
これら 4 つの値の検査を行う関数がそれぞれ用意されている.
is.null() : NULL is.na() : NA is.nan() : NaN is.finite() : 有限か否か is.infinite() : 無限か否か
例えば,ある値が NA かどうかのテストは関数 is.na() で行なう (比較演算子 == では行なえないことに注意) が,これは NaN を代入しても TRUE が返ってしまう.そこで NaN か否か (NA か否かではない) を判定するために is.nan() という関数も用意されている.
is.na(NA) [1] TRUE is.nan(NA) [1] FALSE x <- c(1, NA, 3, 4) is.na(x) [1] FALSE TRUE FALSE FALSE
引数に NA が含まれるとエラーになる関数がある.このような関数に NA が含まれるデータを渡す場合の対処法としては以下のようなものがある.
( a <- c(1,2,NA,4,5,NA) ) [1] 1 2 NA 4 5 NA a[!is.na(a)] # NAを単に取り除く [1] 1 2 4 5 a [1] 1 2 NA 4 5 NA a <- ifelse(is.na(a), 0, a) # NA を 0 に置き換える a [1] 1 2 0 4 5 0
NA を置き換えるのではなく,NA を要素に持つベクトルから,NA を読み飛ばして要素を読み取ることを考える.この場合は以下の様にすればよい.応用すれば 『欠損値と負のデータを除去してデータを読み取る』ことも出来る.
x <- c(1, 2, NA, -4, 5, -6, 7, NA, 9, 10) y <- x[!is.na(x)] # NA 以外の x の要素を y に格納 y [1] 1 2 -4 5 -6 7 9 10 x <- c(1, 2, NA, -4, 5, -6, 7, NA, 9, 10) y <- x[(!is.na(x)) & (x > 0)] # NA と負の値以外の x の要素を y に格納 y [1] 1 2 5 7 9 10
多くの関数は、オプション na.rm=T でNAを除くことができる。
x <- c(1, 2, NA) sum(x) [1] NA sum(x, na.rm=TRUE) [1] 3
> a #こんな行列があるとして [,1] [,2] [,3] [1,] 1 5 8 [2,] 2 6 9 [3,] 3 NA 10 [4,] 4 7 NA > colMeans(a) #列の平均colMeans()を出したいとする。NAは除きたい。 [1] 2.5 NA NA > colMeans(a, na.rm=T) #na.rm=T オプションが使えるが、単にNAを除いた列平均。 [1] 2.5 6.0 9.0 > colMeans(na.omit(a)) #NAを含む行を除くのならna.omit() [1] 1.5 5.5 8.5 > colMeans(!is.na(a)) #!is.na()は..なんだこりゃ、行列から複数のNAを一度には除けない。 [1] 1.00 0.75 0.75 > colMeans(complete.cases(a)) #complete.cases()は colMeans(complete.cases(a)) でエラー: 'x' は少なくとも二次元の配列でなければなりません > colMeans(subset(a,complete.cases(a))) #こうするんだ。na.omit()と同じだがタイプ量が多い。 [1] 1.5 5.5 8.5
complete.cases()の利点は、df[complete.cases(df[,2]),]などとして、NAを除く行を選択することができる。
read.table() で読み込んだデータフレームなどで必要になるかも。
ワンタッチでできる関数はないみたいなので、all()やapply()を使用し工夫。
> a #こんな行列があるとして、 [,1] [,2] [,3] [1,] 1 3 6 [2,] NA 4 7 [3,] 2 5 NA [4,] NA NA NA #na.omit()では2行目以下がみな除かれてしまう。4行目だけ除きたい。 > lineNA <- apply(a, 1, function(x) all(is.na(x))) #すべてNAの行を判定 > lineNA [1] FALSE FALSE FALSE TRUE > a[!lineNA,] [,1] [,2] [,3] [1,] 1 3 6 [2,] NA 4 7 [3,] 2 5 NA
文字列が混じったcsvファイルを読み込んだ時、欠損値がNAにならず空欄のままになることがある。その場合、その空欄のクラスはfactorになっている。 欠損値をもれなくNAにしたいときは、read.csv() でcsvファイルを読み込むとき、オプションに na.strings="" (空欄は欠損値であると明示)をつける。
NULL は属性を取り出す関数が属性値がないときの値として返すなど『適当な結果がない』ことを示すために使わる.NULL と欠損値 NA を混同してしまいがちだが,NA はベクトルの要素となり得るが,NULL はベクトルなのでそれ自身でベクトルの要素にはならない点が異なる.
mode(NULL) # モード "NULL" を持つ [1] "NULL" length(NULL) # 長さが 0 のベクトルである [1] 0 ( a <- 1:3 ) [1] 1 2 3 names(a) # a には names 属性が付いていないので NULL が返る NULL
上の手順を逆手にとって,属性値に NULL を代入して属性値を除去することができる.また,繰り返し文で処理を行うオブジェクトの初期値にも NULL が使われたりする.
names(a) <- c("a", "b", "c") a a b c 1 2 3 names(a) <- NULL a [1] 1 2 3 names(a) NULL x <- NULL # 長さ 0 のベクトル x を用意して for (i in 1:10) x <- append(x, i*i) # x に 1^2, 2^2, 3^2 ... を順に格納する x [1] 1 4 9 16 25 36 49 64 81 100
Inf(無限大・∞)は,数値積分 integrate() を行う際に使うことが出来る.
myfunc <- function(x) x^2 # 関数を定義してから積分する integrate(myfunc, 0, 1) 0.3333333 with absolute error < 3.7e-15 integrate(dnorm, -Inf, 1.96) # 無限を範囲に取ること(広義積分)も可 0.9750021 with absolute error < 1.3e-06