戯言日記

Rの話だと思ったら唐突にサバゲーが混じってくる何か。

ifelseの代わりにcase_whenを流行らせたい

読んで字の如く。知ってる人は間違いなく何の発見もない内容。


分岐条件を与える時にifelseを使う例は多く見かけるが、条件が増えると恐ろしく分かりにくい構造になるのはご存じの通り。

とりあえず「mtcars」のデータセットを題材に、条件分岐を書いてみる。
mutate関数を使いたいので、あらかじめas_tibble()で変換しておく。


mtcars %>% as_tibble() %>%
  dplyr::mutate( Type = 
            ifelse( cyl == 4, "Low",
                    ifelse( cyl == 6, "Middle", 
                            ifelse( gear == 5, "Top", "High" )
                    )))


一目見てどこがどうなってるのか、やや分かりにくい。
ここから更に分岐条件が入り組み始めると、そのうち訳が分からなくなるのは目に見えている。あと最後の部分に「 ) 」が多くて混乱しそう。

という訳で、条件分岐を書く時に改行以外で可読性を上げる方法とかないかな~って調べていたら「case_when」を見つけた。
{dplyr}パッケージの関数なのだが、「R 条件分岐」みたいにググると「if」や「ifelse」、「switch」などが先に引っ掛かるため、最近になってtidyverseにお世話になり始めた人間からすると案外知る機会がなかった。

書き方はこんな感じ。


case_when( 条件 ~ 結果 ) #条件と結果を「 ~ 」で繋ぐ。


これの強力なところは、分岐を1つの括弧の中に並べられること。
さっきの例をcase_whenで書き換えるなら、


mtcars %>% as_tibble() %>%
  dplyr::mutate( Type = dplyr::case_when(
    cyl == 4 ~ "Low",
    cyl == 6 ~ "Middle", 
    cyl == 8 & gear == 5 ~ "Top",
    TRUE ~ "High" )
  )


ものすごく読みやすい。ぱっと見て簡単に条件分岐の構造が把握できる。

ちなみに、条件を複数設定してからTRUEを使うと、残ったデータを纏めて処理することができる。今回の場合だと「cylが4でも6でもなくて、かつgearが5じゃない車種」を全て纏めて扱ってくれる。


可読性を上げようとすると行数が増えるという難点を抱えているので、分岐条件が1~2個なら今まで通りifelseで繋ぐ方が楽だと思う。

ただし明らかにデバックがしやすくなる&括弧の数に悩まされなくなるので、複数の分岐を設定する or 複雑な分岐を設定する場合はどんどん使いたい。