axjack's blog

axjack is said to be an abbreviation for An eXistent JApanese Cool Klutz.

Rで文字列→数値に変換する際、NAs introduced by coercionが出て困った時のtips

次のような変換を考えます。

  • "1名" → 1
  • "2名" → 2
  • "なし" → 0
  • "調査中" → NA

これをdplyrのパイプの中でmutate( case_when(...) )を駆使して実行していたのですが、エラーとなってしまいました。

データフレーム(見栄えのためtibble)

mydf <- tibble( 同居家族 = c("1名","2名","なし","調査中") ) 

ダメな例

mydf %>% mutate(
  同居家族数 = case_when( 
    同居家族 == "なし" ~ 0
    , 同居家族 == "調査中" ~ NA_integer_
    , str_detect(同居家族,"名") ~ as.numeric( str_remove(同居家族,"名") )
    )
  )

上を実行すると次のようなErrorが出ます。

Error: Problem with `mutate()` input `同居家族数`.
x must be an integer vector, not a double vector.
ℹ Input `同居家族数` is `case_when(...)`.
Run `rlang::last_error()` to see where the error occurred.
In addition: Warning message:
In eval_tidy(pair$rhs, env = default_env) : NAs introduced by coercion

ググってみると、なんとなく似たようなissueが上がっておりました。

github.com

頑張って読んでみると、case_when で分岐してもas.numeric( str_remove(同居家族,"名") )が実行されるのはstr_detect(同居家族,"名")の時のみではないっぽいことがわかりました。ということで結局、as.numeric()するときに数値に変換できない文字列が入っていたためエラーになっていた、というわけです。

改善策

改善策としては、面倒臭がらず列を数字に変換できる文字列に一旦変換したのちに、改めてas.numeric()してあげれば良いわけです。

mydf %>% 
  mutate(
    同居家族数 = case_when( 
      同居家族 == "なし" ~ "0"
      , 同居家族 == "調査中" ~ NA_character_
      , str_detect(同居家族,"名") ~  str_remove(同居家族, "名")
    ),
    同居家族数 = as.numeric(同居家族数)
  ) 

実行結果

f:id:axjack:20200726145758p:plain

axjack is said to be an abbreviation for An eXistent JApanese Cool Klutz.