霞と側杖を食らう

ほしいものです。なにかいただけるとしあわせです。[https://www.amazon.jp/hz/wishlist/ls/2EIEFTV4IKSIJ?ref_=wl_share]

RでNaNやNAやInfをデータフレーム全体で置換するときの覚書

 

【用途】
RでデータをいじっていてInfやNaN, NAを何か置換するとき, 気付かないうちに, 文字だと思っていた変数が数値に変わっていることがある. そんなときのための覚書.

【内容】
文字で入れていたはずの変数が中で因子型(factor)になっていると, 置換の操作をしたときに因子を表す数字に変換されていることがあったので, 型をしっかり把握しておくこと. 因子型(factor)から文字型(charactor)にしておけば, 変換されずに済む.

ライブラリ読み込み.

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 3.5.3
## -- Attaching packages ------------------------------------------------------------------------------- tidyverse 1.2.1 --
## √ ggplot2 3.0.0     √ purrr   0.2.5
## √ tibble  1.4.2     √ dplyr   0.7.6
## √ tidyr   0.8.1     √ stringr 1.3.1
## √ readr   1.1.1     √ forcats 0.3.0
## -- Conflicts ---------------------------------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()

具体例のデータフレーム. tibbleにした方が型が見えやすいのでtibbleにしておく.

df <- data.frame(a = c("焼肉", "寿司", "二郎"),
                 b = c(Inf,1,0),
                 c = c(3,3,NaN),
                 d = c(2,NA,1)) %>% as_tibble()

df
## # A tibble: 3 x 4
##   a         b     c     d
##   <fct> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3    NA
## 3 二郎      0   NaN     1

このデータフレームのInfやNaN,NAを0に置き換えたいとする.

df %>% mutate_all(funs(ifelse(is.infinite(.),0,.))) %>% 
  mutate_all(funs(ifelse(is.nan(.),0,.))) %>% 
  mutate_all(funs(ifelse(is.na(.),0,.)))
## # A tibble: 3 x 4
##       a     b     c     d
##   <int> <dbl> <dbl> <dbl>
## 1     2     0     3     2
## 2     1     1     3     0
## 3     3     0     0     1

とやってみると, 焼肉も寿司も二郎もなくなってしまった.

一個ずつ変換を試みる. さらに追加で2種類変換の実験.

df %>% mutate_all(funs(ifelse(is.infinite(.),0,.)))
## # A tibble: 3 x 4
##       a     b     c     d
##   <int> <dbl> <dbl> <dbl>
## 1     2     0     3     2
## 2     1     1     3    NA
## 3     3     0   NaN     1
df %>% mutate_all(funs(ifelse(is.nan(.),0,.)))
## # A tibble: 3 x 4
##       a     b     c     d
##   <int> <dbl> <dbl> <dbl>
## 1     2   Inf     3     2
## 2     1     1     3    NA
## 3     3     0     0     1
df %>% mutate_all(funs(ifelse(is.na(.),0,.)))
## # A tibble: 3 x 4
##       a     b     c     d
##   <int> <dbl> <dbl> <dbl>
## 1     2   Inf     3     2
## 2     1     1     3     0
## 3     3     0     0     1
df %>% replace_na(list(b=0,c=0,d=0))
## # A tibble: 3 x 4
##   a         b     c     d
##   <fct> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3     0
## 3 二郎      0     0     1
df %>% na_if(0)
## # A tibble: 3 x 4
##   a         b     c     d
##   <fct> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3    NA
## 3 二郎     NA   NaN     1

最初の3つは焼肉寿司二郎が2,1,3に置き換わってしまっている.
naに関してはreplace_naが使えるが, リストによる指定が面倒くさい.

因子型となっているのが悪そうなので, 文字型に変換してやってみる.

df$a <- as.character(df$a)

df %>% mutate_all(funs(ifelse(is.infinite(.),0,.)))
## # A tibble: 3 x 4
##   a         b     c     d
##   <chr> <dbl> <dbl> <dbl>
## 1 焼肉      0     3     2
## 2 寿司      1     3    NA
## 3 二郎      0   NaN     1
df %>% mutate_all(funs(ifelse(is.nan(.),0,.)))
## # A tibble: 3 x 4
##   a         b     c     d
##   <chr> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3    NA
## 3 二郎      0     0     1
df %>% mutate_all(funs(ifelse(is.na(.),0,.)))
## # A tibble: 3 x 4
##   a         b     c     d
##   <chr> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3     0
## 3 二郎      0     0     1
df %>% replace_na(list(b=0,c=0,d=0))
## # A tibble: 3 x 4
##   a         b     c     d
##   <chr> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3     0
## 3 二郎      0     0     1
df %>% na_if(0)
## # A tibble: 3 x 4
##   a         b     c     d
##   <chr> <dbl> <dbl> <dbl>
## 1 焼肉    Inf     3     2
## 2 寿司      1     3    NA
## 3 二郎     NA   NaN     1

上手くいっているので全部やると

df %>% mutate_all(funs(ifelse(is.infinite(.),0,.))) %>% 
  mutate_all(funs(ifelse(is.nan(.),0,.))) %>% 
  mutate_all(funs(ifelse(is.na(.),0,.)))
## # A tibble: 3 x 4
##   a         b     c     d
##   <chr> <dbl> <dbl> <dbl>
## 1 焼肉      0     3     2
## 2 寿司      1     3     0
## 3 二郎      0     0     1

なんとか上手くいった. どういうメカニズムでこの問題が起きているか分かってないうえ, もっといい置換方法があるよう気もするが, 場当たり的にとりあえずこれで解決したので書き留めておく.

【記憶の検索キーワード】
NA, NaN, Inf, 置換, 全部, 文字, 数値, 因子, R