はじめに
gganimate
パッケージについて理解したいシリーズです。
この記事では、2次元ランダムウォークのアニメーションをR言語で作成します。
【前の内容】
【他の内容】
【目次】
2次元ランダムウォーク:2方向移動
gganimate
パッケージを利用して、x軸またはy軸方向に移動するランダムウォークのアニメーション(gif画像)を作成します。transition_reveal()
については、transition_reveal.Rmdを参照してください。
利用するパッケージを読み込みます。
# 利用パッケージ library(gganimate) library(tidyverse)
1サンプル
まずは、1個のサンプルを描画します。
移動する方向を示す値をランダムに生成します。
# 試行回数を指定 max_iter <- 100 # ランダムに値を生成 random_val_vec <- sample(c(-1, 1), size = max_iter, replace = TRUE) # ランダムに軸を生成 random_axis_vec <- sample(c("x", "y"), size = max_iter, replace = TRUE) # 確認 random_val_vec[1:10]; random_axis_vec[1:10]
## [1] 1 1 -1 1 -1 -1 -1 1 -1 -1 ## [1] "y" "y" "y" "y" "y" "x" "x" "x" "y" "y"
正方向の移動(1
)または負方向の移動(-1
)をランダムに生成します。
さらに、x軸方向の移動("x"
)またはy軸方向の移動("y"
)をランダムに生成します。
1
とy
の組み合わせが生成されれば、y軸を正の方向に移動します。
生成した値をデータフレームに格納します。
# 元になるデータフレームを確認 tibble::tibble( iteration = c(0, 0, 1:max_iter), random_val = c(0, 0, random_val_vec), axis = c("x", "y", random_axis_vec) ) %>% head()
## # A tibble: 6 x 3 ## iteration random_val axis ## <dbl> <dbl> <chr> ## 1 0 0 x ## 2 0 0 y ## 3 1 1 y ## 4 2 1 y ## 5 3 -1 y ## 6 4 1 y
0回目の結果(スタート地点・原点)に相当する行を加えておきます。
x軸・y軸の値ごとに過去の値の合計を求めます。
# 試行ごとに集計 random_df <- tibble::tibble( iteration = c(0, 0, 1:max_iter), random_val = c(0, 0, random_val_vec), axis = c("x", "y", random_axis_vec) ) %>% tidyr::pivot_wider( names_from = axis, values_from = random_val, values_fill = 0 ) %>% # 横型に変形 dplyr::mutate( x = cumsum(x), y = cumsum(y) ) # 各試行までの合計 head(random_df)
## # A tibble: 6 x 3 ## iteration x y ## <dbl> <dbl> <dbl> ## 1 0 0 0 ## 2 1 0 1 ## 3 2 0 2 ## 4 3 0 1 ## 5 4 0 2 ## 6 5 0 1
pivot_wider()
で、axis
列とrandom_val
列を展開します。
names_from
引数にaxis
を指定します。axis
列の値はx
かy
なので、x
列とy
列ができます。
values_from
引数にrandom_val
を指定します。x
列とy
列の値は、random_val
列の対応する値または欠損値NA
になります。
values_fill
引数に0
を指定すると、NA
ではなく0
になります。
簡単な例で試してみます。
# 簡単な例で確認 tibble::tibble( iteration = c(1, 2), random_val = c(-1, 1), axis = c("y", "x") ) %>% tidyr::pivot_wider( names_from = axis, values_from = random_val )
## # A tibble: 2 x 3 ## iteration y x ## <dbl> <dbl> <dbl> ## 1 1 -1 NA ## 2 2 NA 1
追加されたx
列とy
列それぞれの累積和をcumsum()
で計算します。
アニメーションを作成します。
# 2次元ランダムウォークを作図 anim <- ggplot(random_df, aes(x = x, y = y)) + geom_point(color = "hotpink", size = 5) + # 散布図 geom_path(color = "hotpink", size = 1, alpha = 0.5) + # 折れ線 geom_hline(yintercept = 0, color = "red", linetype = "dashed") + # 水平線 geom_vline(xintercept = 0, color = "red", linetype = "dashed") + # 垂直線 gganimate::transition_reveal(along = iteration) + # フレーム coord_fixed(ratio = 1) + # アスペクト比 labs(title = "Random Walk", subtitle = "iter : {frame_along}") # gif画像を作成 gganimate::animate(plot = anim, nframes = max_iter+1, fps = 10)
目安として、と
の線を引いています。
複数サンプル
続いて、複数個のサンプルを同時に描画します。
移動する方向を示す値をランダムに生成します。
# 試行回数を指定 max_iter <- 100 # サンプルサイズを指定 sample_size <- 10 # ランダムに値を生成 random_value_vec <- sample(x = c(-1, 1), size = max_iter*sample_size, replace = TRUE) # ランダムに軸を生成 random_axis_vec <- sample(x = c("x", "y"), size = max_iter*sample_size, replace = TRUE) # 確認 random_val_vec[1:10]; random_axis_vec[1:10]
## [1] 1 1 -1 1 -1 -1 -1 1 -1 -1 ## [1] "x" "y" "y" "y" "x" "y" "x" "x" "x" "x"
試行回数max_iter
とサンプルサイズsample_size
を指定して、max_iter * sample_size
個の値と軸を生成します。
生成した値をデータフレームに格納します。
# 元になるデータフレームを確認 tidyr::tibble( iteration = rep(c(0, 0, 1:max_iter), each = sample_size), id = rep(1:sample_size, times = max_iter+2), random_val = c(rep(0, times = sample_size*2), random_value_vec), axis = c(rep(c("x", "y"), each = sample_size), random_axis_vec) ) %>% dplyr::filter(iteration == 1) %>% # 1回目の結果を表示 head()
## # A tibble: 6 x 4 ## iteration id random_val axis ## <dbl> <int> <dbl> <chr> ## 1 1 1 1 x ## 2 1 2 1 y ## 3 1 3 1 y ## 4 1 4 1 y ## 5 1 5 1 x ## 6 1 6 -1 y
全てのサンプルに対して0回目の結果に相当する行を加えます。
また、random_***_vec
の1番目の要素をサンプル1の1回目の結果、2番目の要素をサンプル2の1回目の結果と続けて、sample_size + 1
番目の要素をサンプル1の2回目の結果と続けて割り当てることにします。
2つの0
と1
からmax_iter
までの整数をそれぞれsample_size
個に複製して、試行回数(iteration
)列とします。
1
からsample_size
までの整数をmax_iter + 2
回繰り返して、サンプル番号(id
)列とします。
sample_size * 2
個の0
の後にrandom_value_vec
を続けて、乱数(random_val
)列とします。
sample_size
個の"x"
と"y"
の後にrandom_axis_vec
を続けて、軸(axis
)列とします。
サンプルごとに過去の値を合計します。
# 試行ごとに集計 random_df <- tidyr::tibble( iteration = rep(c(0, 0, 1:max_iter), each = sample_size), id = rep(1:sample_size, times = max_iter+2) %>% as.factor(), random_val = c(rep(0, times = sample_size*2), random_value_vec), axis = c(rep(c("x", "y"), each = sample_size), random_axis_vec) ) %>% tidyr::pivot_wider( names_from = axis, values_from = random_val, values_fill = 0 ) %>% # 横型に変形 dplyr::group_by(id) %>% # サンプルごとにグループ化 dplyr::mutate( x = cumsum(x), y = cumsum(y) ) %>% # 各試行までの合計 dplyr::ungroup() # グループ化の解除 # 3サンプルの3回目までの結果 random_df %>% dplyr::filter(iteration <= 3, id %in% 1:3)
## # A tibble: 12 x 4 ## iteration id x y ## <dbl> <fct> <dbl> <dbl> ## 1 0 1 0 0 ## 2 0 2 0 0 ## 3 0 3 0 0 ## 4 1 1 1 0 ## 5 1 2 0 1 ## 6 1 3 0 1 ## 7 2 1 0 0 ## 8 2 2 -1 1 ## 9 2 3 1 1 ## 10 3 1 -1 0 ## 11 3 2 0 1 ## 12 3 3 0 1
作図用に、サンプル番号(id
列の値)を因子型にしておきます。
pivot_wider()
で、axis
列とrandom_val
列を展開します。
id
列が同じ値でグループ化して、サンプルごとにcumsum()
で累積和を計算します。
アニメーションを作成します。
# 2次元ランダムウォークを作図 anim <- ggplot(random_df, aes(x = x, y = y, color = id)) + geom_point(size = 5, show.legend = FALSE) + # 散布図 geom_path(size = 1, alpha = 0.3, show.legend = FALSE) + # 折れ線 geom_hline(yintercept = 0, color = "red", linetype = "dashed") + # 水平線 geom_vline(xintercept = 0, color = "red", linetype = "dashed") + # 垂直線 gganimate::transition_reveal(along = iteration) + # フレーム coord_fixed(ratio = 1) + # アスペクト比 labs(title = "Random Walk", subtitle = "iter : {frame_along}") # gif画像を作成 gganimate::animate(plot = anim, nframes = max_iter+1, fps = 10)
sample_size
個の折れ線グラフが描画されます。
最終結果は次のようになります。
# 最終結果 random_df %>% dplyr::filter(iteration == max_iter) %>% ggplot() + geom_point(mapping = aes(x = x, y = y, color = id), size = 5, show.legend = FALSE) + # 散布図 geom_path(data = random_df, mapping = aes(x = x, y = y, color = id), size = 1, alpha = 0.3, show.legend = FALSE) + # 折れ線 geom_hline(yintercept = 0, color = "red", linetype = "dashed") + # 水平線 geom_vline(xintercept = 0, color = "red", linetype = "dashed") + # 垂直線 coord_fixed(ratio = 1) + # アスペクト比 labs(title = "Random Walk", subtitle = paste0("iter : ", max_iter))
以上で、2次元ランダムウォークを作図できました。この例では、x軸またはy軸に対して並行に移動しました。次は、平面上の全ての方向に移動する場合を扱います。
おわりに
このタイプのランダムウォークは知ってましたが、360°方向に変化するパターンもあるんですね。というわけで次はそっちのタイプをやります。
【次の内容】