Rのデータハンドリング
はじめに
Rで学ぶデータサイエンス:マシンラーニング第2版の回帰の章を読んでいると、変数の総当りでモデルを評価する方法が記載されていた。
そのコードがエンジニアではない私には面白かったので、内容をおさらいしておく。コード自体は01の組み合わせの一覧を生成する方法。
剰余と整数商
この本では剰余と整数商を使った組み合わせの一覧の作り方をコードに組み混んでいた。剰余と整数商は下記の通りで、余りと除算した際の整数部分の数字のこと。
1:10 %% 2 #剰余 [1] 1 0 1 0 1 0 1 0 1 0 1:10 %/% 2 #整数商 [1] 0 1 1 2 2 3 3 4 4 5
Rコード
剰余と整数商を使った組み合わせの一覧の作るコードは下記の通り。書籍のものを参考に一部修正した。
col_num <- 5 row_num <- 2^col_num mat <- matrix(rep(0, length = row_num * col_num), nrow = row_num) mat for (i in 1:row_num) { tmp <- i for (j in 1:col_num) { tmp1 <- tmp %% 2 #剰余 if(tmp1 == 1) mat[i, j] <- 1 tmp <- tmp %/% 2 #整数除算 if(tmp == 0) break } } mat [,1] [,2] [,3] [,4] [1,] 1 0 0 0 [2,] 0 1 0 0 [3,] 1 1 0 0 [4,] 0 0 1 0 [5,] 1 0 1 0 [6,] 0 1 1 0 [7,] 1 1 1 0 [8,] 0 0 0 1 [9,] 1 0 0 1 [10,] 0 1 0 1 [11,] 1 1 0 1 [12,] 0 0 1 1 [13,] 1 0 1 1 [14,] 0 1 1 1 [15,] 1 1 1 1 [16,] 0 0 0 0
別パターン
01の組み合わせは、 \(k\)を個数だとすると、\(2^k\)で組み合わせ総数を計算できる。そして、少し並び替えると法則がみえる。
mat %>% as.data.frame() %>% arrange(., V4, V3, V2, V1) %>% select(V4, V3, V2, V1) V4 V3 V2 V1 1 0 0 0 0 2 0 0 0 1 3 0 0 1 0 4 0 0 1 1 5 0 1 0 0 6 0 1 0 1 7 0 1 1 0 8 0 1 1 1 9 1 0 0 0 10 1 0 0 1 11 1 0 1 0 12 1 0 1 1 13 1 1 0 0 14 1 1 0 1 15 1 1 1 0 16 1 1 1 1
例えば0の行については、\(2^3\)、\(2^2\)、\(2^1\)、\(2^0\)という順番で0の数が減っているので、この組み合わせで数列を作れば、01の組み合わせの一覧が取得できる。
n <- 4 mat <- matrix(rep(0, length = 2^n * n), ncol = n) for(i in 1:n){ tmp <- rep(c(0, 1), each = 2^(n-i)) mat[, i] <- rep(tmp, 2^(i-1)) } mat [,1] [,2] [,3] [,4] [1,] 0 0 0 0 [2,] 0 0 0 1 [3,] 0 0 1 0 [4,] 0 0 1 1 [5,] 0 1 0 0 [6,] 0 1 0 1 [7,] 0 1 1 0 [8,] 0 1 1 1 [9,] 1 0 0 0 [10,] 1 0 0 1 [11,] 1 0 1 0 [12,] 1 0 1 1 [13,] 1 1 0 0 [14,] 1 1 0 1 [15,] 1 1 1 0 [16,] 1 1 1 1
あとはこれを関数化しておく。ここでは、リストを使う。
zeroichi <- function(n){ mat <- vector(mode = "list", length = n) for(i in 1:n){ tmp <- rep(c(0, 1), each = 2^(n-i)) mat[[i]] <- rep(tmp, 2^(i-1)) } res <- mat %>% map_dfc(.x = ., .f = c) } df <- zeroichi(4) # A tibble: 16 x 4 V1 V2 V3 V4 <dbl> <dbl> <dbl> <dbl> 1 0 0 0 0 2 0 0 0 1 3 0 0 1 0 4 0 0 1 1 5 0 1 0 0 6 0 1 0 1 7 0 1 1 0 8 0 1 1 1 9 1 0 0 0 10 1 0 0 1 11 1 0 1 0 12 1 0 1 1 13 1 1 0 0 14 1 1 0 1 15 1 1 1 0 16 1 1 1 1 df %>% dplyr::mutate_if(is.numeric, as.character) %>% dplyr::group_by(V1, V2, V3, V4) %>% dplyr::summarise(cnt = n()) %>% dplyr::filter(cnt > 1) # A tibble: 0 x 5 # Groups: V1, V2, V3 [0] # … with 5 variables: V1 <chr>, V2 <chr>, V3 <chr>, V4 <chr>, cnt <int>
こういうのは、エンジニアの人とかは当たり前なんだろうな…。