老化によるset.seed忘れを防ぎたい
Rひとりアドベントカレンダー1日目。
set.seed()は乱数の種を設定する関数ということはよく知られている。 乱数の種を設定することで、乱数に再現性がとれるようになる。 例えば以下の2行のコードはまとめて実行することで毎回同じ結果を返す。
> set.seed(1) > rnorm(5) [1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078
だがここでもう一回rnorm()を実行したらどうなるだろう。 なんとなく同じrnorm(5)の結果が得られるように思えないだろうか。 答えはブーである。
> rnorm(5) [1] -0.8204684 0.4874291 0.7383247 0.5757814 -0.3053884
同じrnorm(5)の結果を得るにはset.seed(1)を再び実行する必要がある。
> set.seed(1) > rnorm(5) [1] -0.6264538 0.1836433 -0.8356286 1.5952808 0.3295078
ハハッ、こんなん当たり前っしょとか思ってる人、dplyr::sample_n()を利用する際もちゃんとset.seed()を併せて実行しているだろうか。
set.seed(1) result <- iris %>% sample_n()
こんなの絶対にset.seed()の実行忘れる自信がある。10回中1回は絶対忘れる。俺は日々老化している。
ということで、dplyrのイシューにもsample_n()のオプションにseed入れたほうがよくね?という提案がある。却下されているが。
却下されている理由としては、汎用的なwithr::with_seed()があるからというものである。
使い方はこんな感じ。
library(withr) > with_seed(1, iris %>% sample_n(5)) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.4 1.5 0.2 setosa 2 5.7 2.8 4.5 1.3 versicolor 3 5.4 3.0 4.5 1.5 versicolor 4 6.3 2.8 5.1 1.5 virginica 5 4.7 3.2 1.6 0.2 setosa > with_seed(1, iris %>% sample_n(5)) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.4 1.5 0.2 setosa 2 5.7 2.8 4.5 1.3 versicolor 3 5.4 3.0 4.5 1.5 versicolor 4 6.3 2.8 5.1 1.5 virginica 5 4.7 3.2 1.6 0.2 setosa
確かにこうしておけば、seedとの一体感が生まれるし何より実行忘れがない。 そしてwith_preserve_seed()を使えば、いちいち指定しなくても最初にset.seed()したシードで統一できる。
library(withr) > set.seed(1) > with_preserve_seed(iris %>% sample_n(5)) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.4 1.5 0.2 setosa 2 5.7 2.8 4.5 1.3 versicolor 3 5.4 3.0 4.5 1.5 versicolor 4 6.3 2.8 5.1 1.5 virginica 5 4.7 3.2 1.6 0.2 setosa > with_preserve_seed(iris %>% sample_n(5)) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.4 1.5 0.2 setosa 2 5.7 2.8 4.5 1.3 versicolor 3 5.4 3.0 4.5 1.5 versicolor 4 6.3 2.8 5.1 1.5 virginica 5 4.7 3.2 1.6 0.2 setosa
今後はwith_seed()そしてwith_preserve_seed()を使っていくことにする。
どうかな。