⭐️expand.grid()とdata.frame()では水準の扱い方が異なる
ちょっとしたメモ。
2015-11-26 追記 📝 @dichika さんが検証してくださいました。Rの組み込み関数のソースを見たい場合には https://github.com/wch/r-source が良いですね。参考になります。
data.frame()
では、変数内の大きさ(ベクトルの長さ)が等しい必要があるが、expand.grid()
を使うとよしなに要因ごとの組み合わせからなるデータフレームを作成する。
age <- seq(from = 20, to = 40, by = 5) data.frame(性別 = c("男性", "女性"), 年齢 = age) # Error in data.frame(性別 = c("男性", "女性"), 年齢 = age) : # arguments imply differing number of rows: 2, 5 expand.grid(性別 = c("男性", "女性"), 年齢 = age) # 性別 年齢 # 1 男性 20 # 2 女性 20 # 3 男性 25 # 4 女性 25 # ... (省略) # 10 女性 40
入力を減らしてデータフレームを作れるので模擬データ等の生成に便利である。
今日作業してたら、このexpand.grid()
の挙動がdata.frame()
と微妙に異なっていることに気がついた。何が違うのかというと、要因クラスの水準の順番である。こんな感じ。
data.frame(性別 = c("男性", "女性"), 年齢 = c(26, 24)) %>% .$性別
## [1] 男性 女性
## Levels: 女性 男性
expand.grid(性別 = c("男性", "女性"), 年齢 = c(26, 24)) %>% .$性別
## [1] 男性 女性 男性 女性
## Levels: 男性 女性
data.frame()
では、正確に文字の並び(?)で水準が定義されているが、expand.grid()
では、要因の順序が入力順で定義されてしまう。
理由はよくわからない。R言語の構造上の問題なのかもしれない。
おまけ
そもそも論として、今回のような性別という変数は、水準の大きさに優劣のない名義尺度であって強制的に文字列が要因クラスになってしまうdata.frame()
の使用はナンセンスな感じなので、dplyr::data_frame()
を使うのが今時だろう(data.frame()
で文字を文字列として扱うためにはstringsAsFactors引数でFALSEを指定しておけば良い)。加えて、expand.grid()
もtidyr::expand()
を使った方が良いかもしれない。
data.frame(性別 = c("男性", "女性"), 年齢 = c(26, 24), stringsAsFactors = FALSE) %>% .$性別
## [1] "男性" "女性"
dplyr::data_frame(性別 = c("男性", "女性"), 年齢 = c(26, 24)) %>% .$性別
## [1] "男性" "女性"
dplyr::data_frame(性別 = rep(c("男性", "女性"), 3), 出身地 = c("北海道", "岡山県", "岡山県", "神奈川県", "福島県", "東京都"), 年齢 = purrr::rdunif(n = 6, b = 30, a = 20)) %>% tidyr::expand(性別, 出身地, 年齢)
## Source: local data frame [50 x 3]
##
## 性別 出身地 年齢
## (chr) (chr) (dbl)
## 1 女性 北海道 22
## 2 女性 北海道 24
## 3 女性 北海道 26
## 4 女性 北海道 27
## 5 女性 北海道 30
## 6 女性 岡山県 22
## 7 女性 岡山県 24
## 8 女性 岡山県 26
## 9 女性 岡山県 27
## 10 女性 岡山県 30
## .. ... ... ...