Rのこと。

記事は引っ越し作業中。2023年中までに引っ越しを完了させてブログは削除予定

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>

こういうのは、エンジニアの人とかは当たり前なんだろうな…。