10. Series

Note

ここまで解説した機能でABMを回すことはできますが、この章では一連の設定を自動化して実行するSeriesという機能を紹介します。はじめにSeriesについて概観し、実際に簡単な例で実際の使い方を解説します。

10.1 Seriesについて

(1) 目的

Seriesはここまで解説した一連のrABMの設定や実行に関するスクリプトをchunkとして保存し、任意のchunkを組み合わせて実行する機能です。この機能は大きく二つの目的で使用することができます。

  • Gameオブジェクトをrun_Gameによって回すだけではなく、変数やフィールドの設定からの一連の流れで毎回のシミュレーションを回す場合

  • ABMの実行が一度のrun_Gameを実行するだけでは終了せず、複数のrun_Gameを組み合わせる必要がある場合(たとえばいったん収束値に至ったうえで、そこに何らかのランダムな変化を**State**フィールドに与えて、さらにrun_Gameを実行する場合など)

(2) 基礎的な使用方法

SeriesはABMに関するものだけではなく、通常のスクリプトに関しても使用することができます。概要を掴むうえでは、こちらの方が分かりやすいため、以下の例では、通常の簡単なスクリプトをSeriesとして実行しています。

library(rABM)

はじめに各スクリプトをChunk({...})としてくくります。なお1行のみのスクリプトはChunk(x <- 1)のように書いても内部で処理されますが2行以上の場合にはエラーになります。したがって、常に{ }でくくる癖をつけたほうが無難です。

# チャンクを
step1 <- Chunk({
  x <- 1
})

step2 <- Chunk({
  y <- x + 1
})

step3 <- Chunk({
  z <- y + 1
})

これらの各ChunkをSeries()として定義することで、Seriesオブジェクトが作成されます。

S <- Series(step1, step2, step3)

このSeriesオブジェクトの中身は、通常通りプリントすることで確認できます。

S
<Series>
[chunks]
$step1
{
    x <- 1
}

$step2
{
    y <- x + 1
}

$step3
{
    z <- y + 1
}

[default]
  (none)
-------------------
n of chunks  : 3 
  chunks     : step1, step2, step3 
n of defaults: 0 
  defaults   :  
-------------------

Seriesオブジェクトは、run_Series()関数で、実行することができます。

S2 <- run_Series(Series = S)
[Series plan]
step1 -> step2 -> step3 

Series implementing...
  Step 1: step1
  Step 2: step2
  Step 3: step3
Series implementation DONE!

アウトプットが格納されたS2オブジェクトには、run_Seriesが実行された環境下での値が$valuesという中に格納されています。

S2
$values
$values$z
[1] 3

$values$y
[1] 2

$values$x
[1] 1


$series_plan
[1] "step1" "step2" "step3"

$series_seed
[1] 1775201070

$error_log
list()

$implementation_took
[1] "00:00:00.000"

10.2 応用的な利用方法

(1) 複数のChunkを用意しておき、runごとに変える

run_Seriesでは実際に利用するChunkをseries_planで指定することができます。このことを利用して、あらかじめ複数のchunkを用意することで、分析ごとに簡単に変えることができます。

# step1_1とstep1_2を両方用意しておく
step1_1 <- Chunk({x <- 1})
step1_2 <- Chunk({x <- 10})
step2   <- Chunk({y <- x^2})

# Series
S <- Series(step1_1, step1_2, step2)

# step1_1の方を利用して計算する
S2 <- run_Series(S, series_plan = c("step1_1", "step2"))
[Series plan]
step1_1 -> step2 

Series implementing...
  Step 1: step1_1
  Step 2: step2
Series implementation DONE!

上記の例と同様に、step1_2の方を指定することで結果を変えられます。

(2) default値を指定しておく

あらかじめdefault値を指定しておくことで、run_Seriesの実行時に、その値が環境に存在することを前提に計算がなされます。

# x = 2というdefault値を入れておく
step2 <- Chunk({y <- x^2})
S <- Series(step2, default = list(x = 2))

# step2だけ回しても、x = 2が環境に存在するため、計算が可能となる
S2 <- run_Series(S, series_plan = "step2")
[Series plan]
step2 

Series implementing...
  Step 1: step2
Series implementation DONE!
S2
$values
$values$y
[1] 4

$values$x
[1] 2


$series_plan
[1] "step2"

$series_seed
[1] 1775201071

$error_log
list()

$implementation_took
[1] "00:00:00.000"

Default値をrun_Seriesの引数inputを変えることで変更できる。

S3 <- run_Series(S, series_plan = "step2", input = list(x = 3))
[Series plan]
step2 

Series implementing...
  Step 1: step2
Series implementation DONE!
S3
$values
$values$y
[1] 9

$values$x
[1] 3


$series_plan
[1] "step2"

$series_seed
[1] 1775201071

$error_log
list()

$implementation_took
[1] "00:00:00.000"

(3) 結果変数のみ取得する

run_Series関数のsimplify_output引数をTRUEにすると、シミュレーションに変数のみアウトプットで返します。

S4 <- run_Series(S, series_plan = "step2", simplify_output = TRUE, verbose = FALSE)
S4
$y
[1] 4

$x
[1] 2

10.3 実際のABMでの使用用法

本章の最後に実際のABMでの使用方法について、ごく簡単な例を用いて解説します。

以下のモデルにおいて更新そのものはエージェントに毎回1が足されることが共通ですが、エージェントの初期値を変えたいと思います。このようなときにSeriesが使用できます。

# 二種類の初期値を用意する
money_pattern1 <- Chunk({money <- 1:5})
money_pattern2 <- Chunk({money <- 100:105})

# 後の操作は共通
create_G <- Chunk({
  # act_FUNを作成する
  add_money <- function(){self$money <- self$money + 1}
  
  # Gameオブジェクトに格納する
  G <- Game(State(money), Act(add_money))
})

run <- Chunk({G2 <- run_Game(G, plan = c("add_money"))})

# Seriesとして定義
S <- Series(money_pattern1, money_pattern2, create_G, run)

# money_pattern2の方で回してみる
S2 <- run_Series(S, series_plan = c("money_pattern2", 
                                    "create_G",
                                    "run"),
                 verbose = FALSE,
                 simplify_output = TRUE)
[plan] 
add_money
 
[stop_FUN] 
stop times at 2

The initial values at time 1 were saved.

Ready to run......
   start time  : 1
   current time: 2
Finished at time 2 

Simulation took 00:00:00.009 (hh:mm:ss.mmm)
# 結果を確認してみる
S2$G2$money
[1] 101 102 103 104 105 106