library("tidyr")
library("dplyr")
library("pipeR")
とあるホクソエムさんが悩んでおりました。
tidyrでダミー変数を作成する(赤ペン先生希望) - My Life as a Mock Quant
少ない脳みそを使ってちょっと考えてみました。
df <- data.frame(id = 1:10,
feature = c(1, NaN, 2, 2, 2, NaN, NaN, 3, 3, 1))
df
## id feature
## 1 1 1
## 2 2 NaN
## 3 3 2
## 4 4 2
## 5 5 2
## 6 6 NaN
## 7 7 NaN
## 8 8 3
## 9 9 3
## 10 10 1
元ブログでNA (欠損値)を与えているところをNaN (非数)にします。その理由は下で書きます(犯人はヤス)。あとの処理はおんなじ。selectのところだけNaNに変更。
df %>>% spread(key = feature,
value = feature,
fill = 0) %>>%
select(-contains("NaN")) %>>%
mutate_each(funs(ifelse(. >= 1, 1, 0)), -id)
## id 1 2 3
## 1 1 1 0 0
## 2 2 0 0 0
## 3 3 0 1 0
## 4 4 0 1 0
## 5 5 0 1 0
## 6 6 0 0 0
## 7 7 0 0 0
## 8 8 0 0 1
## 9 9 0 0 1
## 10 10 1 0 0
要点を先に。何気なく頻繁に使うNA。こいつの挙動には気をつけたほうが良さ気。teramonagiさんはダミーデータの作成時に欠損値を意味するNAを使っていたのですが、これをそのままspreadにかけてしまったところが罠だったようです。
df <- data.frame(id = 1:10,
feature = c(1, NaN, 2, 2, 2, NaN, NaN, 3, 3, 1))
df$feature
## [1] 1 NaN 2 2 2 NaN NaN 3 3 1
df.na <- data.frame(id = 1:10,
feature = c(1, NA, 2, 2, 2, NA, NA, 3, 3, 1))
df.na$feature
## [1] 1 NA 2 2 2 NA NA 3 3 1
この段階では何も問題がなさそう。
ところがどっこい、spreadでdf$featureの値を列名に置き換えるという処理を行うさい、NAの存在が思わぬ障害を招いていました。
df.na %>>% spread(key = feature,
value = feature,
fill = 0) %>>%
select(-contains("NA"))
## data frame with 0 columns and 10 rows
どうしてこのようなことになるのでしょうか。
spreadした時点での列名はid, 1, 2, 3, NAの5列からなっているはずですが…
df.na %>>% spread(key = feature,
value = feature,
fill = 0) %>>% colnames()
## [1] "id" "1" "2" "3" NA
NAの部分は認識されていない(?)みたいです。これが元で返り値がエラーになったのだと思われます。
というわけで、欠損値ではなく、とりあえずなんらかしらが存在するよ、という意味でNaNを使って対処しました。
df %>>% spread(key = feature,
value = feature,
fill = 0) %>>% colnames()
## [1] "id" "1" "2" "3" "NaN"
NaNであれば列名として認識してくれるみたいです。
理由は説明できません。他の(R言語の構造に詳しい)方が解説してくれることを願います。現場からは以上です。