Note of Pediatric Surgery

腸内細菌、R、ときどき小児外科

{dplyr}のパイプの中でNAを0に置換する

Rにおいて欠損値NAを0に変換するのは、Rを覚えたての頃につまづくことのうちの1つじゃないかと思います。いろいろ方法はあると思いますが、{dplyr}を使ってパイプの中で処理をする方法はあまり見つからなかったので、まだまだビギナーの自分にとっては結構大きい知見だったので共有しておきます。あまり大した知識ではないですし、常識なのかもしれないけど。

1. パイプ演算子を使わない方法

恐らく、パイプ演算子を使わないのならばこの方法が一番楽かと思います。

df <-
  data.frame(P1 = c(NA,1,6,3,NA),
             P2 = c(3,NA,2,6,6),
             Q1 = c(5,NA,NA,NA,2),
             Q2 = c(2,1,NA,5,NA))
P1 P2 Q1 Q2
1 NA  3  5  2
2  1 NA NA  1
3  6  2 NA NA
4  3  6 NA  5
5 NA  6  2 NA

こういうデータがあったとしてNAを0に置換したい時。

df[is.na(df)] <- 0

としてしまえば置換できます。

P1 P2 Q1 Q2
1  0  3  5  2
2  1  0  0  1
3  6  2  0  0
4  3  6  0  5
5  0  6  2  0



2. {dplyr}でパイプ演算子を使って処理する方法

1.の方法は簡単なのですが、dplyrのチェーンの中で一気に処理している時に、いちいちdfというオブジェクトに代入してから処理するのも面倒、というか美しくもないと思います。また、特定の列だけNAを0に置換したい時とかは少し面倒なスクリプトが必要になるかと。そこでdplyrを使う方法を書いておきます。

library(dyplr)
df <-
  data.frame(P1 = c(NA,1,6,3,NA),
             P2 = c(3,NA,2,6,6),
             Q1 = c(5,NA,NA,NA,2),
             Q2 = c(2,1,NA,5,NA))

df %>%
  tbl_df() %>%
  mutate_all(funs(ifelse(is.na(.),0,.)))

とすると

# A tibble: 5 x 4
P1    P2    Q1    Q2
<dbl> <dbl> <dbl> <dbl>
  1     0     3     5     2
2     1     0     0     1
3     6     2     0     0
4     3     6     0     5
5     0     6     2     0

と上手く置換できていると思います。この方法のメリットは列名での指定が容易なことで、例えば

# Pで始まる列だけを置換
df %>%
  tbl_df() %>%
  mutate_at(vars(starts_with("P")), funs(ifelse(is.na(.),0,.)))
# A tibble: 5 x 4
P1    P2    Q1    Q2
<dbl> <dbl> <dbl> <dbl>
  1     0     3     5     2
2     1     0    NA     1
3     6     2    NA    NA
4     3     6    NA     5
5     0     6     2    NA

ということもできます。ちなみにmutate_at()はstart_with()をvars()でwrapしないと上手く動いてくれないことが多いです。ココらへんのことはTechnically, technophobic.にとても詳しく書かれているので、{dplyr}ユーザーはぜひ目を通しておくべきと思います。

notchained.hatenablog.com

他にも

# 1を含む列だけを置換
df %>%
  tbl_df() %>%
  mutate_at(vars(matches("1",.)), funs(ifelse(is.na(.),0,.)))
# A tibble: 5 x 4
P1    P2    Q1    Q2
<dbl> <dbl> <dbl> <dbl>
  1     0     3     5     2
2     1    NA     0     1
3     6     2     0    NA
4     3     6     0     5
5     0     6     2    NA

ということもできて、フレキシブルに対応できるかと思います。でも、よく調べたら他にもたくさん方法はありそうなので、StackOverflowの記事も参考にしてみてください。Enjoy!

stackoverflow.com