【R言語】いい加減NAとNaNとNULL（ついでにInf）の違いをはっきりさせておく

# NA、NaN、NULL、Infとは何か
## ざっくりまとめ
| 値 | 由来 |日本語名 |具体例|説明|データ型確認関数|イメージ画像|
|:--------:|:--------:|:--------:|:--------:|:--------|:--------|:--------:|
| NA |Not Available | 欠損値 |NA|本来データが存在しているが、何らかの理由でデータが存在していない状態を示す|is.na()|<img src="https://qiita-image-store.s3.amazonaws.com/0/135663/a6d4bd77-c650-36b3-cfbd-5db73b228fb5.png" width=100>|
| NaN |Not a Number | 非数値|0/0|計算不可能な式の結果として表される|is.nan()|<img src="https://qiita-image-store.s3.amazonaws.com/0/135663/d0b8b580-7c76-a562-bde9-909595d741f0.png" width=100>|
| NULL  | null |非存在 |NULL|もともと値が存在していないことを示す|is.null()|![nc69175.jpg](https://qiita-image-store.s3.amazonaws.com/0/135663/ffcfc4e4-3044-0707-b934-b85782556f84.jpeg)|
| Inf |  Infinity| 無限大 |1/0|無限に発散する計算結果として表される|is.infinite()|![110622infinity_02.jpg](https://qiita-image-store.s3.amazonaws.com/0/135663/b28c28d5-cefa-a464-23ae-7c64ee522cda.jpeg)|


## データ型の観点から理解する
### Rのデータ型概要
| データ型       |       データ型の確認関数 |    表記例    |欠損値|
|:----------------:|:--------------|:------------------|:------------------|
| 実数 |is.numeric |    3、-1.5、 .1、1e+2、1.4e-2、**Inf**、-**Inf**、**NaN** |**NA_real_**|
| 文字列 | is.character | 'abc'、"森進一"、"髙田延彦\n星新一"|**NA_character_**|
| 整数  |     is.integer | 1L （単に1だけだと実数型になる）|**NA_integer_**|
| 複素数 |  is.complex | 2+3i         |**NA_complex_**|
| 論理  |    is.logical | TRUE、FALSE、T、F  |**NA**|
| **NULL**   |    is.null | NULL |なし|
### Inf、NaNについて
Inf、NaNは実数型の一種です。もともと、Infは無限に発散する式の計算結果を示すもの、NaNは計算不可能な式の結果を示すものであり、どちらも数値計算の結果です。よって、実数型にあてはまります。

```R
# 値を準備
(nan_num <- 0/0) # NaN
(inf_num <- 1/0) # Inf
# NaN、Infそれぞれ確認
is.nan(nan_num)# [1] TRUE
is.infinite(inf_num)# [1] TRUE
# 実数型かどうか確認
is.numeric(nan_num) # [1] TRUE
is.numeric(inf_num) # [1] TRUE
```
注意点として、NaNはis.naで調べた結果がTRUEになるので覚えておきましょう。

```
is.na(nan_num) # [1] TRUE
```

### NAについて
一番右端の列の、**NA_real_**や**NA_character**などは見慣れない表記なのではないでしょうか。実はRの内部では、各データ型に対して欠損値**NA**を用意しています。例えば、文字列のベクトルの中にある欠損値NAは、**文字列型のNA**とし、実数型のベクトルの中にある欠損値NAは、**実数型のNA**として扱っています。実際にRで確認したものが以下になります。



```R
# 3番目の要素にNAを入れたベクトルを用意
chr <- c("a","b",NA)
num <- c(1L,9L,NA)
# データ型を確認
typeof(chr[3]) # [1] "character"
typeof(num[3]) # [1] "numeric"
# NAかどうか確認
is.na(chr[3]) # [1] TRUE
is.na(num[3]) # [1] TRUE
# NA_character_かどうか確認
identical(chr[3],NA_character_) # [1] TRUE
identical(num[3],NA_character_) # [1] FALSE
# NA_integer_かどうか確認
identical(chr[3],NA_integer_) # [1] FALSE
identical(num[3],NA_integer_) # [1] TRUE
```
### NULLについて
NULLはデータが存在しないことを示すデータ型です。NAは本来データが存在しているが何らかの理由で存在しないことを示すが、NULLはもともと存在しないことを示します。
存在しないのに、NULLという表記がある事自体が少しややこしいです。

```R
class(NULL) # [1] "NULL"
is.null(NULL) # [1] TRUE
```
### データ型についてまとめ

- NaN、Inf
    - 実数型
- NA　
    - 各データ型それぞれに存在
- NULL
    - データが存在しないことを示すデータ型

ということがわかりました。

# NA、NaN、NULL、Infが原因でハマりやすいポイント
## NAやNaN対してどんな計算をしてもNA、NaNになる

```R
# NAを含んだ計算
NA + 8 # [1] NA
2 * NA # [1] NA
sum(c(1, 2, 4, NA)) # [1] NA
# NaNを含んだ計算
NaN + 8 # [1] NaN
NaN * 2 # [1] NaN
sum(c(1, 2, 4, NaN)) # [1] NaN
# ちなみに、NAとNaN両方含まれる計算をすると、先に計算される方が優先される
NaN * 10 # [1] NaN
NA * NaN * 10 # [1] NA
```
データに対して何らかの集計・統計処理などをしているとき、結果がNAで出てきてしまうことはよくある。そんなときはパソコンをバンバンするのではなく、まずはデータにNAが含まれていることを疑ったほうがよい。NAの探し方はこの記事を読み進めると出て来る。

## NULLはベクトルの要素になれない
```R
# NULLを含んだベクトル？
null_vec <- c(1,2, NULL, 4)
null_vec # [1] 1 2 4
length(null_vec) # [1] 3
```
だってそもそも、存在しない存在なので。

# NA、NaN、Infの対処法
NA、NaN、Infが存在するデータについて、以下の3点で対処法を整理します

- NA、NaN、Infが含まれるかどうか確認する
- NA、NaN、Infを別の値で置換する
- NAやNaNがある行を取り除く

```R
# 例としてNAなどが含まれたirisデータを準備
data(iris)
iris[,1:4][iris[,1:4] %% 1.1 == 0] <- NA
iris[,1:4][iris[,1:4] %% 0.9 == 0] <- NaN
iris[,1:4][iris[,1:4] %% 0.7 == 0] <- Inf
#  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          5.1         Inf          Inf         0.2  setosa
# 2          4.9         3.0          Inf         0.2  setosa
# 3          4.7         3.2          1.3         0.2  setosa
# 4          4.6         3.1          1.5         0.2  setosa
# 5          5.0         NaN          Inf         0.2  setosa
# 6          NaN         3.9          1.7         0.4  setosa
```
## NA、NaN、Infが含まれるかどうか確認する
### まずはsummaryがおすすめ。
最も手軽に各列の欠損値の状況を調べることができます

```R
summary(iris)
#  Sepal.Length  Sepal.Width   Petal.Length    Petal.Width        Species  
# Min.   :4.3   Min.   :2.0   Min.   :1.000   Min.   :0.1   setosa    :50  
# 1st Qu.:5.1   1st Qu.:3.0   1st Qu.:1.700   1st Qu.:0.2   versicolor:50  
# Median :6.0   Median :3.1   Median :4.700   Median :1.3   virginica :50  
# Mean   :Inf   Mean   :Inf   Mean   :  Inf   Mean   :Inf                  
# 3rd Qu.:6.7   3rd Qu.:3.7   3rd Qu.:5.875   3rd Qu.:2.0                  
# Max.   :Inf   Max.   :Inf   Max.   :  Inf   Max.   :Inf                  
# NA's   :29    NA's   :17    NA's   :20      NA's   :18 
```
上記の出力結果を読み解き方を、一番左のSepal.Length列を例に説明すると、

- *NA's   :29*
    - 欠損値(NAもしくはNaN)が29個含まれていることがわかる
- *Mean   :Inf*
    - 平均がInfなので、データにInfが含まれていることがわかる
    
と読み解くことができます。
### 各列の平均値などは無しで、純粋にNA、NaN、Infの数だけを集計したい
sapply()と、is.na()、sum()を組み合わせることで可能です。

```R
sapply(iris, function(y) sum(is.na(y)))
# Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
#          29           17           20           18            0

sapply(iris, function(y) sum(is.nan(y)))
# Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
#          19           13           12           12            0

sapply(iris, function(y) sum(is.infinite(y)))
# Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
#           7           20           21            8            0 
```

## NA、NaN、Infを別の値で置換する
### データフレーム全体に対して置換をしたい
```R
# データフレーム全体のNAを0で置換
iris[is.na(iris)] <- 0
# データフレーム全体のNaNを0で置換
iris[is.nan(iris)] <- 0
# データフレーム全体のInfを0で置換
iris[is.infinite(iris)] <- 0
```
### データフレームの列に対して置換をしたい
```R
#Sepal.Length列のNAを0で置換
iris$Sepal.Length <- ifelse(is.na(iris$Sepal.Length),0,iris$Sepal.Length)
#Sepal.Length列のNaNを0で置換
iris$Sepal.Length <- ifelse(is.nan(iris$Sepal.Length),0,iris$Sepal.Length)
#Sepal.Length列のInfを0で置換
iris$Sepal.Length <- ifelse(is.infinite(iris$Sepal.Length),0,iris$Sepal.Length)
```

## NAやNaNがある行を取り除く
na.omit()を使うことで、NA（NaN）を含む全ての行を削除することができます

```R
iris2 <- na.omit(iris)
# NAが削除されたかを確認
sapply(iris2, function(y) sum(is.na(y)))
# Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
#           0            0            0            0            0  #消えてる！
nrow(iris2)
# [1] 79
```
na.omit()で処理した後は、必ずnrow()で行数を確認するようにしましょう。本題から逸れますが、もし想定以上に減っていた場合は平均値などで置換することも想定したほうがよいかもしれません。