linearsolve
¶import linearsolve as ls
import numpy as np
import pandas as pd
# numpy v1の表示を使用
np.set_printoptions(legacy='1.21')
# 警告メッセージを非表示
import warnings
warnings.filterwarnings("ignore")
後に続く章では,実物的景気循環(RBC)モデルとNew Keynsianモデル(Dynamic Stochastic General Equilibrium Model,略してDSGEモデルとも呼ばれる)を考える。それらのモデルでは,消費者は効用を最大化し,企業は利潤を最大化する。そのような最適化問題を解き,一般均衡での動学方程式を導出する作業は高度な数学的な知識を要求するため,このサイトの範囲を超えることになる。従って,それぞれのモデルの考えを説明した後,シミュレーションを使いデータとの整合性などを検討する。この章では,そのために使用するlinearsove
というパッケージの使い方を説明する。
実物的景気循環モデルやNew Keynsianモデルの均衡式は複雑な非線形となっており,また将来の変数に対する期待が重要な役割を果たす。従って,次の2つのステップを踏んでシミュレーションをおこなうことになる。
このプロセスを自動化してくれるのがlinearsolve
(リンク)である。2の均衡の計算方法はについては,
linearsolve
はKlein (2000)を採用している。その詳細については割愛するが,1の対数線形近似について簡単に説明する。
{note}
`linearsolve`を使用するためには,事前にインストールする必要がある。MacのターミナルやWindowsのAnaconda Promptでは,次のコマンドでインストールすることができる。
```
pip install linearsolve
```
$t=0,1,2,..$の離散時間を考えよう。$t$時点での変数$X$を$X_t$とする。産出量や資本ストックなどをイメージすれば良いだろう。さらに次の変数を定義する。
以前,マクロ変数をトレンドと変動(トレンドからの%乖離)に分離する分析をおこなった。その際,$\bar{X}_t$をトレンドとすると,変動は次式で近似できることも説明した。
$$ \frac{X_{t+1}-\bar{X}_t}{\bar{X}_t}\approx\log\left(\frac{X_{t+1}}{\bar{X}_t}\right) $$実は,これが正しく対数線形近似の考え方なのである。$X=\bar{X}_t$として,この式を変形すると次のようになる。
$$ \begin{align*} \frac{X_{t}-X}{X}&\approx\log\left(\frac{X_{t}}{X}\right)\\ \frac{X_{t}}{X}&\approx 1+\log\left(\frac{X_{t}}{X}\right)\\ X_{t}&\approx X(1+x_t) \end{align*} $$この式が$X_t$の対数線形近似となる。更に,$Z_t^a$の線形近似を考えてみよう。$Z^a$を定常状態と置いて上の計算の2行目に$X_t=Z_t^a$と$X=Z^a$を代入してみる。
$$ \begin{align*} \frac{Z_{t}^a}{Z^a}&\approx 1+\log\left(\frac{Z_{t}^a}{Z^a}\right)\\ &\approx 1+a\log\left(\frac{Z_{t}}{Z}\right)\\ Z_t^a&\approx Z^a(1+az_t) \end{align*} $$(eq:14-linearapprox)
ここで$z_t=\log\left(\dfrac{Z_t}{Z}\right)$は$Z_t$の%乖離を表している。式eq:14-linearapproxが$Z_t^a$の対数線形近似であり,$a=1$の場合を包含する形となっている。
例として,人口成長も技術進歩もないソロー・モデルの資本蓄積方程式を考えよう($L=1$を仮定する)。
$$ K_{t+1}=sK_t^a+(1-\delta)K_t $$式が示すように,$K_{t+1}$と$K_{t}$は非線形の関係にある。次の変数を定義して,対数線形近似をおこなう。
それぞれの項にパーセント乖離の線形近似を適用する。
$$ \begin{align} K(1+k_{t+1})&=sK^a(1+ak_t)+(1-\delta)K(1+k_t)\\ 1+k_{t+1}&=\frac{s}{K^{1-a}}(1+ak_t)+(1-\delta)(1+k_t)\\ &=\delta(1+ak_t)+(1-\delta)(1+k_t)\\ k_{t+1}&=[1-(1-a)\delta]k_t\\ \end{align} $$これでパーセント乖離の変数である$k_{t+1}$と$k_{t}$の線形式が導出できた。$k_t$の係数は正の値であり$1$より小さいので,定常状態$0$は安定的だとわかる。
次のコブ・ダグラス生産関数を考えよう。
$$ Y_t=A_tK_t^\alpha $$ここで$A_t$はTFPショックと考えることができる。また定常状態は次式で与えられるとしよう。
$$ Y=AK^\alpha $$$t$期の生産関数を定常状態の生産関数で除した結果を対数化することで簡単に%乖離を計算できる。
$$ \frac{Y_t}{Y}=\frac{A_t}{A}\left(\frac{K_t}{K}\right)^\alpha \quad\Rightarrow\quad y_t = a_t+\alpha k_t $$この場合,線形近似ではなく正確な関係を表している。同じ結果を上のeq:14-linearapprox式を使って導出してみよう。
$$ \begin{align*} Y(1+y_t)&=A(1+a_t)K^\alpha(1+\alpha k_t)\\ 1+y_t&=(1+a_t)(1+\alpha k_t)\\ &=1+\alpha k_t+a_t+\alpha a_tk_t\\ y_t&=\alpha k_t+a_t \end{align*} $$最後の行では$\alpha a_tk_t=0$としている。%乖離の積は非常に小さな値であるためであり,eq:14-linearapprox式を導出する上で発生した誤差を表している(誤差は無視できるほど非常に小さい)。
linearsolve
の使い方¶対数線形近似を理解できたと思うので,linersolve
を使って次のステップでシミュレーションを進める。
Series
として保存する。linearsolve.model
を使いシミュレーションのための最終準備(シミュレーションの情報が詰まったオブジェクトを作成)をする。シミュレーションをおこなう上で2つの変数を区別することも重要となるので次の点を抑えておこう。
またシミュレーションのの中で決定される変数は全て「内生変数」と呼ぶ。
以下では2つの例を使い具体的にシミュレーションのコードの書き方を説明をする。
$A$は全要素生産性(TFP)を表しており,次式に従って変化すると考えよう。
$$ A_{t+1}=A_t^{\rho}e^{u_{t+1}}, \quad 0<\rho<1 $$(eq:14-tfp)
ここで,底の$e$はネイピア数であり,指数の$u_{t+1}$はショック変数のホワイト・ノイズであり,正規分布に従うと仮定する。
$$ u_{t}\sim\mathcal{N}(0,\sigma^2) $$パラメータは$\rho$と$\sigma$の2つだけである。パラメータの値を入れたSeries
を変数parameter
に割り当てる。
parameters = pd.Series({'rho':0.9,
'sigma':0.0078**2})
parameters
ここでは辞書を使ってSeries
を作成している。sigma
の値は日本のTFPに関して計算した数値を設定している。
内生変数名のリスをを作成する。その際,次の順番で並べる。
ショック項があるストック変数(内生変数)の変数名
ショック項がないストック変数(内生変数)の変数名
フロー変数(他の内生変数)の変数名
この例では,ショック項があるストック変数A
のみとなる。また,リストの要素として含める変数名をA
としても良いが,計算結果ではA
の対数線形近似の変数が返される。それを見越して,ここではa
を使うことにする。このように指定するする方が,後で分かりやすいだろう。
var_names = ['a']
次に,外生的ショックを表す変数名のリストを作成するが,var_namesと同じ順番に並べる。
shock_names = ['u']
定常状態とは,ショック項が0
であり,A
が一定となる状態を指す。このステップでは,定常状態での値を返す関数を作成する。関数名をequilibrium_equations
とする。この例での定常状態では次の条件を満たしている。
次に,非確率的な定常状態での均衡条件を返す関数を定義する。
variables_forward
: $t+1$期(来期)の変数variables_current
: $t$期(当該期)の変数parameters
:ステップ1で設定したパラメータの値を含む変数parameters
Numpy
のarray
def equilibrium_equations(variables_forward, variables_current, parameters):
fwd = variables_forward #1
cur = variables_current #2
p = parameters #3
tfp = cur['a']**p['rho']/fwd['a']-1 #4
return np.array([tfp]) #5
<コードの説明>
#1
: t+1期の変数をfwd
に割り当てる。
#2
: t期の変数をcur
に割り当てる。
#3
: ステップ1のparameters
をp
に割り当てる。
#4
: 定常状態でのTFPの式を使い,左辺が0になるように整理し,その右辺をtfp
に割り当てる。
$$ A_{t+1}=A_t^{\rho} \quad\Rightarrow\quad 0=\frac{A_t^{\rho}}{A_{t+1}}-1 $$
equilbirium_equations
関数を単に指定するだけだが, linearmodels
はcur
とfwd
をSeries
として扱うことになるため,変数を['a']
の形で指定する必要がある。#5
: #4
の変数をarray
として返す。
#4
以外にも均衡式がある場合は,np.array
の一次元配列として#5
に含めることになる。ls
のmodel
という関数を使いシミュレーションの最終準備をおこない(初期化し),tfp_model
に割り当てる。
equations
:ステップ2で定義した関数を指定する。variables
:ステップ2で設定した内生変数のリストを指定する。exo_states
:ショック項があるストック変数名を指定する。複数の場合はリストとして指定する。A
のみなのでa
を指定する。endo_state
:ショック項がないストック変数名を指定する。複数の場合はリストとして指定する。costates
:コントロール変数名を指定する。複数の場合はリストとして指定する。shock_names
:ステップ2で設定したショック変数のリストを指定する。e_a
)が使われる。parameters
:ステップ1で設定したパラメータの値を含むSeries
を指定する。linearsolve
のmodel
オブジェクトが返される。その中に様々な情報が含まれており,それを使いシミュレーションをおこなう。tfp_model = ls.model(equations = equilibrium_equations,
variables = var_names,
exo_states = 'a',
# endo_states = None,
# costates = None,
shock_names = shock_names,
parameters = parameters)
最初に定常状態の値を確認しよう。tfp_model
のメソッドcompute_ss()
(ss
は定常状態を指すsteady stateの略)を使うと自動で計算してくれる。その際,引数に計算の初期値をリストとして与える。linearsolve
が定常値を「計算する」という意味は,定常値を「探す」ということと等しい。その際,探す出発点となる値が「計算の初期値」である。この例では変数が1つなので[1.1]
のようにする。複数ある場合は,ステップ2で設定したvar_names
の順番に合わせて初期値を並べる必要がある。
tfp_model.compute_ss([1.1])
上のコードを評価すると,tfp_model
には.ss
という属性が追加され,計算結果は属性.ss
でアクセスすることが可能である。
tfp_model.ss
ここで示しているのは,linearmodels
は1.1
を出発点として定常値を探し始め,最終的に1.0
を探し出したということだ。
次にシミュレーションのための対数線形近似をおこなう。tfp_model
には.approximate_and_solve(log_linear=True)
というメソッドが用意されており,それを使うとtfp_model
の対数線形近似を計算し,tfp_model
に組み込むことになる。
tfp_model.approximate_and_solve(log_linear=True)
結果はtfp_model
のメソッド.solved()
を使うと表示できる。
print(tfp_model.solved())
ここで表示された式を考えてみよう。$A_t$の定常状態での値は1
であり,式eq:14-tfpを次のように書ける。
$a_{t}\equiv\log\left(\dfrac{A_{t}}{1}\right)\approx\dfrac{A_t-1}{1}$(定常値からの乖離の割合)を使い,この式の両辺を対数化すると
$$ a_{t+1}=\rho a_t+u_{t+1} $$となり($\log(1)=0$を思い出そう),上の式と同じになる。この結果から,上の式は近似ではなく同じ式である事が分かる。
{note}
`print(tfp_model.solved())`のコードが表示しているのは2行は文字列であり,改行が2回(`\n\n`)入っている。これを利用して次のコードで2行目の式だけを取り出す事ができる。
```
print(tfp_model.solved().split('\n\n')[1])
```
* `split()`は文字列を引数`'\n\n'`で分割し,結果をリストとして返すメソッドである。
* `[1]`はリストの1番目の要素を取り出している(0番目は`Solution to the...`となる)。
t=0
期は定常状態でa[0]=0
としよう。更に,t=1
期にショック項が1%上昇したとしよう(u[1]=1%
)。この場合,a[1]=1%
となる事が分かる。これがインパクト効果である。インパクト後,ショック項は0
に張り付いたままとなり,a
の値は次のように変化することになる。
a[0]=0
a[1]=1%
a[2]=0.95a[1]=0.95x1%=0.95%
a[3]=0.95a[2]=0.95x0.95x1%=0.9025%
a[4]=0.95a[3]=0.95x0.95x0.95x1%=0.857375%
......
時間が経つに連れて徐々に減少することになり,一般的には次の式で表すことができる。
$$ a[t]=0.95^{t-1}\times 1\%,\qquad\quad t=1,2,3,... $$この一連の「出力」がインパルス反応と呼ばれる。
では,実際にインパルス反応を計算し図示してみよう。ホワイト・ノイズのショック$u_t$のインパルス反応を計算するには,tfp_model
のメソッドimpulse()
を使う。
T
:シミュレーションのの期間t0
:何期目にショックを発生させるかを指定shocks
:ショックの大きさ(定常状態からの乖離,デフォルトは0.01
)shocks={'u':0.05}
。tfp_model
に辞書として追加される。u
DataFrame
.irs
(Impulse ReSponseの略)でアクセスできるので,キーu
を使ってDataFrame
を表示することが可能となる。まずメソッド.impulse()
で計算しよう。
tfp_model.impulse(T=50, t0=5, shocks={'u':0.05})
次に,属性.irs
を使って辞書を抽出し,キーu
を使ってDataFrame
を表示する。
tfp_model.irs['u'].head(9)
5
番目の行のみでu
が0.05
になっているのが確認できる。同様に,a
も0.05
に跳ね上がっているが,インパクト後は徐々に減少しているのがわかる。
縦軸を%表示にして,このDataFrame
をプロットしてみよう。
( 100*tfp_model.irs['u'] ).plot(lw=3, alpha=0.5, grid=True)
pass
この図のa
はA_t
の定常状態からの%乖離を表していることを思い出そう。t=0
からt=4
の5期間はショックがない定常状態である。t=5
に5%
の正のショックが発生し,t=6
以降のショックは0
に戻っている。一方,A
の%乖離であるa
はゆっくりと減少し,分かりにくいが50
期間過ぎても0%
になっていない。例えば,一期間を1四半期と考えた場合,ショック項の影響は(50-5)/4=11.25
年経った後でも残っていることになる。persistenceと呼ばれるこのような性質が景気循環を理解する上で重要な鍵となる。
今までの説明では,それぞれのステップ毎にセル内でコードを書き実行した。しかし,一旦コードにエラーがないと確認できた後は,1つのセルにコードをまとめることを勧める。例えば,パラメーターの値を変えて様々なパターンの結果を確認したいとしよう。1つのセルにコードをまとめると1回のコードの実行で結果を表示できる便利さがある。
# パラメーターの値
parameters = pd.Series({'rho':0.9,
'sigma':0.0078**2})
# 変数のリスト
var_names = ['a']
shock_names = ['u']
# 定常状態での均衡の関数
def equilibrium_equations(variables_forward, variables_current, parameters):
fwd = variables_forward
cur = variables_current
p = parameters
tfp = cur['a']**p['rho']/fwd['a']-1
return np.array([tfp])
# モデルの初期化
tfp_model = ls.model(equations = equilibrium_equations,
variables = var_names,
exo_states = 'a',
# endo_states = None, # 内生変数(stock)
# costates = None, # 内生変数(control)
shock_names=shock_names,
parameters = parameters)
# 定常状態の計算
tfp_model.compute_ss([1.1])
ss = tfp_model.ss
print(f'定常値\n{ss.index[0]}: {ss.iloc[0]:.3f}\n')
# 対数線形近似
tfp_model.approximate_and_solve(log_linear=True)
print('対数線形近似\n', tfp_model.solved().split('\n\n')[1], sep='')
# インパルス反応の計算
tfp_model.impulse(T=50, t0=5, shocks={'u':0.05})
# プロット
( 100*tfp_model.irs['u'] ).plot(lw=3, alpha=0.5, grid=True)
pass
インパルス反応は,ある一期間のみにショック項が変化する場合の分析となる。一つのショックの時系列的な効果を検討する上では有用な手法である。一方で,実際経済ではショックが断続的もしくは連続的に発生していると考えることができる。そのような状況を捉えた確率的シミュレーションをおこなおうというのが,ここでの目的である。
linearmodels
には,そのためのメソッド.stoch_sim()
が実装されている。
seed
(オプション): Numpy.random
を使いランダム変数を発生させるが,seed
とはランダム変数の「種」という意味である。seed
に同じ数字を設定すると同じランダム変数が生成されることになる。同じ「種」からは同じランダム変数を発生させることができる,ということである。T
:シミュレーションの期間(デフォルトは51)covariance_matrix
:ショック変数の分散共分散行列[[0.5]]
のようにリストのリストで設定する。(デフォルトは[[1]]
)[[0.5,0.1],[0.1,2]]
のようなパターンで設定する。(デフォルトは[[1,0],[0,1]]
)この例で,0.5
と2
が2つのショック項の分散であり,0.1
が共分散となる。 戻り値:
なし
* 結果はtfp_model
にDataFrame
として追加され,属性simulated
で抽出できる。
tfp_model.stoch_sim(seed=12345, T=200,
covariance_matrix=[[parameters['sigma']]])
結果の一部を表示してみる。
tfp_model.simulated.head()
図示してみよう。
tfp_model.simulated.plot()
pass
ショック項u
は細かく上下している一方,a
は持続的に上昇もしくは減少し定常値0
から乖離することがわかる。景気循環におけるマクロ変数の動きと似ていいる様に見えないだろうか。
式eq:14-tfpの両辺に対数をとると次式となる。
$$ \log(A_{t+1}) = \log(A_t) + u_{t+1} $$この式に基づいて次のようにしても結果は同じである
ステップ3の(4)を次のコードと入れ替える。
tfp = p['rho']*np.log(cur['a'])-np.log(fwd['a'])
ステップ6を
tfp_model.approximate_and_solve(log_linear=False)
もしくは
tfp_model.approximate_and_solve()
にする。ここでlog_linear
は対数線形近似をおこなうかどうかを設定する引数であり,デフォルトはTrue
。False
の場合は線形近似となる。
次の例としてTFPが確率的に変動するソロー・モデルを考えよう。均衡は次の3つの式で表される。
$$ Y_t = A_t K_t^{\alpha} $$(eq:14-prod_fn)
$$ K_{t+1} = sY_t + (1-d) K_t $$(eq:14-capital_accum)
$$ \log A_{t+1} = \rho \log A_t + u_{t+1} $$(eq:14-tfplog)
eq:14-tfplog式は全要素生産性の変動を表しており,eq:14-tfp式と同じである。また$u_{t}\sim\mathcal{N}(0,\sigma^2)$とする。
4つパラメータの値を入れたSeries
を変数parameter
に割り当てる。
parameters = pd.Series({'alpha':0.36,
's':0.1,
'd':0.07,
'rho':0.551,
'sigma':0.0078**2})
parameters
ここでは辞書を使ってSeries
を作成している。rho
とsigma
の値は日本のTFPに関して計算した数値を設定している。
内生変数名のリスをを作成する。その際,次の順番で並べる。
また対数線形近似されることを念頭に小文字で変数名を設定することにする。
var_names = ['a','k','y']
次に,外生的ショックを表す変数名のリストを作成する。複数ある場合は,var_names
と同じ順番に並べる。この例では,a
のみにショック項があるので次のようにする。
shock_names = ['u']
非確率的定常状態での値を返す関数を作成する。関数名はequilibrium_equations
とする。この例での非確率的定常状態では次の条件を満たしている。
variables_forward
: $t+1$期(来期)の変数variables_current
: $t$期(当該期)の変数parameters
Numpy
のarray
def equilibrium_equations(variables_forward, variables_current, parameters):
fwd = variables_forward #1
cur = variables_current #2
p = parameters #3
tfp = p['rho']*np.log(cur['a'])-np.log(fwd['a']) #4
production_function = cur['a']*cur['k']**p['alpha'] - cur['y'] #5
capital_change = p['s']*cur['a']*cur['k']**p['alpha'] + \
(1-p['d'])*cur['k'] - fwd['k'] #6
return np.array([tfp, production_function, capital_change]) #7
<コードの説明>
#1
: t+1期の変数をfwd
に割り当てる。
#2
: t期の変数をcur
に割り当てる。
#3
: ステップ1のparameters
をp
に割り当てる。
#4
: (非確率的)定常状態でのTFPの式を使い,左辺が0になるように整理し,その右辺をtfp
に割り当てる。
$$ \begin{align*} \log(A_{t+1}) &=\rho\log(A_t) \\ &\Downarrow \\ 0 &=\rho\log(A_{t})-\log(A_{t+1}) \end{align*} $$
equilbirium_equations
関数を単に指定するだけだが, linearmodels
はcur
とfwd
をSeries
として扱うことになるため,変数を['a']
の形で指定する必要がある。#5
: 生産関数の式を使い,左辺が0になるように整理し,その右辺をproduction_function
に割り当てる。
$$ \begin{align*} Y_{t}&=A_tK_t^{a} \\ &\Downarrow \\ 0&=A_tK_t^{a}-Y_t \end{align*} $$
#6
: 資本の蓄積方程式を使い,左辺が0になるように整理し,その右辺をcapital_change
に割り当てる。
$$ \begin{align*} K_{t+1}&=sA_tK_t^{a}+(1-d)K_t \\ &\Downarrow \\ 0&=sA_tK_t^{a}+(1-d)K_t-K_{t+1} \end{align*} $$
#7
: #4
〜#6
の値をarray
として返す。
ls
のmodel
という関数を使いシミュレーションの最終準備をおこない(初期化し),solow_model
に割り当てる。
equations
:ステップ2で定義した関数を指定する。variables
:ステップ2で設定した内生変数のリストを指定する。exo_states
:ショック項があるストック変数名を指定する。複数の場合はリストとして指定する。A
のみなのでa
を指定する。endo_state
:ショック項がないストック変数名を指定する。複数の場合はリストとして指定する。costates
:コントロール変数名を指定する。複数の場合はリストとして指定する。shock_names
:ステップ2で設定したショック変数のリストを指定する。e_a
)が使われる。parameters
:ステップ1で設定したパラメータの値を含むSeries
を指定する。linearsolve
のmodel
オブジェクトが返される。その中に様々な情報が含まれており,それを使いシミュレーションをおこなう。solow_model = ls.model(equations = equilibrium_equations,
variables = var_names,
exo_states = 'a',
endo_states = 'k',
costates = 'y',
shock_names=shock_names,
parameters = parameters)
最初に定常状態の値を確認しよう。solow_model
のメソッドcompute_ss()
を使うと自動で計算してくれる。その際,引数に計算の初期値をリストとして与える。ステップ2で設定したvar_names
の順番に合わせて初期値を並べる。
solow_model.compute_ss([1, 5, 2])
上のコードを評価すると,solow_model
には.ss
という属性が追加され,それを使い計算結果を表示できる。
solow_model.ss
次にシミュレーションのための対数線形近似をおこなう。solow_model
には.approximate_and_solve(log_linear=True)
というメソッドが用意されており,それを使うとsolow_model
の対数線形近似を計算し,solow_model
に組み込むことになる。
solow_model.approximate_and_solve(log_linear=True)
結果はsolow_model
のメソッド.solved()
を使うと表示できる。
print(solow_model.solved())
ここでa
,k
,y
は定常状態からの%乖離を表している。これらの式が「モデルを解いた結果」を示しており,次の特徴がある。
a
とk
)のt+1
期の値は,t
期の値とt+1
期のショックに依存している。t
期のストック変数とt+1
期のショック変数の値が分かれば,t+1
期の全ての変数の値が明らかになる体系になっている。例えば,t=0
期が定常状態(a[0]=k[0]=y[0]
)としてt=1
期にショック項u[1]
が1%
上昇したとしよう。上の式からu[1]=a[1]=y[1]=1%
となることが分かる。
t=0
期は定常状態でa[0]=k[0]=y[0]=0
としよう。そしてt=1
期にショック項が1%
上昇し(u[1]=1%
),その後0
に戻ると仮定しよう。この場合,
a[1]=y[1]=1%
であり,k[1]=0
となる事が分かる。これがインパクト効果である。a[2]=0.551・a[1]
,k[2]=0.07・a[2]
,y[2]=a[2]+0.35・k[2]
となり時間が経つに連れて変化することになる。このインパルス反応を計算して図示してみよう。
ホワイト・ノイズのショック$u_t$のインパルス反応を計算するには,solow_model
のメソッドimpulse()
を使う。引数は次の3つとなる。
T
:シミュレーションのの期間t0
:何期目にショックが発生するかを指定shocks
:ショックの大きさ(%)(デフォルトは0.01)solow_model.impulse(T=50, t0=5)
計算結果はsolow_model
に辞書として追加される。
u
DataFrame
辞書は属性.irs
でアクセスできるので,キーu
を使いDataFrame
を表示してみよう。
solow_model.irs['u'].head(9)
5
番目の行でu
は1.0
になっている。同様に,a
とy
も1.0
にジャンプしているが,資本ストックの%乖離であるk
は,5
番目の行で0
のままである。これは式eq:14-capital_accumが示すように,t
期の産出Y
の変化はt+1
期の資本ストックに影響を与えており,時間的なラグが発生しているためである。また6
行目からk
は徐々に増加していることがわかる。この結果は,資本ストックの変化には時間がかかるという特徴を反映したものといえる。
プロットしてみよう。
( 100*solow_model.irs['u'] ).plot(subplots=True, figsize=(6,8), grid=True)
pass
産出と資本ストックの%乖離の変化は大きく異なる。動物で例えると,産出はカモシカのように動きが素早いが,資本ストックは象のように動きがスローである。前者はフロー変数であり,後者はストック変数であるためであり,それぞれの変数の特徴が反映されたプロットとなっている。
ここでは上のコードを一つのセルにまとめて,全てを同時に実行し結果を表示してみよう。
# パラメーターの値
parameters = pd.Series({'alpha':0.36,
's':0.1,
'd':0.07,
'rho':0.551,
'sigma':0.0078**2})
# 変数名
var_names = ['a','k','y']
shock_names = ['u']
# 定常状態での均衡の関数
def equilibrium_equations(variables_forward, variables_current, parameters):
fwd = variables_forward
cur = variables_current
p = parameters
tfp = p['rho']*np.log(cur['a'])-np.log(fwd['a'])
production_function = cur['a']*cur['k']**p['alpha'] - cur['y']
capital_change = p['s']*cur['a']*cur['k']**p['alpha'] + \
(1-p['d'])*cur['k'] - fwd['k']
return np.array([tfp, production_function, capital_change])
# モデルの初期化
solow_model = ls.model(equations = equilibrium_equations,
exo_states = ['a'],
endo_states = ['k'],
costates = ['y'],
shock_names=['u'],
parameters = parameters)
# 定常状態の計算
solow_model.compute_ss([1,5,2])
print('定常値')
for i in range(len(solow_model.ss)):
print(f'{solow_model.ss.index[i]}: {solow_model.ss.iloc[i]:.3f}')
print('')
# 対数線形近似
solow_model.approximate_and_solve(log_linear=True)
print('対数線形近似')
for s in solow_model.solved().split('\n\n')[1:]:
print(s, sep='')
# インパルス反応の計算
solow_model.impulse(T=50, t0=5)
# プロット
(100*solow_model.irs['u']).plot(subplots=True, layout=[2,2],
figsize=(10,5), grid=True)
pass
次にメソッド.stoch_sim()
を使って確率的シミュレーションをおこなってみよう。
seed
(オプション): Numpy.random
を使いランダム変数を発生させるが,seedとはランダム変数の「種」という意味。seed
に同じ数字を設定すると同じランダム変数が生成されることになる。T
:シミュレーションの期間(デフォルトは51)cov_mat
:ショック変数の分散共分散行列[[0.5]]
のようにリストのリストで設定する。(デフォルトは[[1]]
) 返り値:
なし
* 結果はsolow_model
にDataFrame
として追加され,属性simulated
で抽出できる。
ショック項u
の分散の値は0.0078であり,これは日本のTFPを推定した際の残差の分散である。この値を使ってシミュレーションをおこなおう。
solow_model.stoch_sim(seed=12345, T=200,
covariance_matrix=[parameters['sigma']])
結果の一部を表示してみる。
solow_model.simulated.head()
{warning}
この`DataFrame`の値はランダム変数を発生させて計算した結果である。従って,引数`seed`を設定しない場合は,シミュレーションを実行する度に異なる結果が発生する。しかし,以下で示す表や値はシミュレーションを行うごとに異なる結果となるが,方向性としては概ね変わらない。
DataFrame
を図示してみよう。
ax_ = ( 100* solow_model.simulated[['a','u']] ).plot(subplots=True,
layout=(1,2),
grid=True,
figsize=(12,4),
color='k')
( 100*solow_model.simulated[['k','y']] ).plot(grid=True, ax=ax_[0,0])
pass
この図の特徴:
a
とy
の動きは殆ど同じである。また上下の動きはが激しく,定常値0
を跨いだ動きが多い。k
の動きは緩やか。定常値0
からの乖離の方向が比較的に長く持続する傾向にある。即ち,persistenceの特徴が強い。変動の大きさを確認するために標準偏差を計算してみよう。
solow_model.simulated[['y','k','a']].std()
a
とy
の値はは殆ど同じである。一方,k
の標準偏差は小さく,a
とy
の半分以下である。この特徴は相関係数からも確認できる。
solow_model.simulated[['y','k','a']].corr()
y
とa
の相関は非常に高く,k
との相関は低い。また,3つの変数は正の相関があることがわかる。
次にpersistenceを考えてみよう。k
の変動幅は小さいががpersistenceが大きいことが図から確認できる。実際に自己相関係数で確認してみよう。
var_list = ['y','k','a']
for v in var_list:
ac = solow_model.simulated[v].autocorr()
print(v,f': {ac:.3f}')
y
とa
に比べてk
の自己相関係数が非常に高いことがわかる。