シミュレーションは、自然現象や社会現象をモデルを使って再現するもので、 コンピュータ上で専用のアプリケーションを使って行われています。 ここでは、Sageを使って「MathematicaによるOR」4章で紹介されている経済モデル をシミュレーションする方法を紹介します。
モデルの作成には、論理的なモデルを使用する場合とデータに適合する数学モデルを データから見つける方法があります。数学モデルの場合には、モデルが実際データを うまく表現しているかを調べるためにデータを教師用データと検証用データに分けて モデルの表現能力を確認します。
%%HTML
<link rel="stylesheet" type="text/css" href="css/sage_table_form.css">
# jupyter用のdisplayメソッド
from IPython.display import display, Latex, HTML, Math, JSON
# sageユーティリティ
load('script/sage_util.py')
モデルを作成する前に、今回使用する経済データがどのようなものか見てみましょう。 経済データには、1965年から1989年までの、所得、消費、投資、政府支出が含まれて います。
それでは、Sageを使って経済データを読み込み、どのような分布をしているか調べてみましょう。
sageでは、豊富なPythonのライブラリを使うことができるため、 データの読み込み処理がとても楽に行えます。
今回は、csvライブラリを使ってカンマ区切りのCSV形式のデータ (Econometrics.txt)を読み込み、 Year, Ct, Yt, It, Gtの値をリスト変数にセットします。
# テストデータ(CSV形式)の読み込み
import csv
fileName = 'data/Econometrics.txt'
csvfile = open(fileName) # CSVファイルの読み込み
reader = csv.reader(csvfile) # CSVリーダーの取得
hdr = reader.next() # ヘッダを読む
# データを読む
Year = []; CtData =[]; YtData = []; ItData = []; GtData = [];
for row in reader:
Year.append(N(row[0]))
CtData.append(N(row[1]))
YtData.append(N(row[2]))
ItData.append(N(row[3]))
GtData.append(N(row[4]))
csvfile.close()
# print hdr
# print Year, YtData, CtData, ItData, GtData
以下に読み込んだ政府支出、消費、投資、所得をプロットしています。 これから、消費と所得の類似性や投資の変動が大きいことが見て取れます。
# データの関係
gtPlot = list_plot(GtData, rgbcolor='red', figsize=3)
ctPlot = list_plot(CtData, rgbcolor='red', figsize=3)
itPlot = list_plot(ItData, rgbcolor='red', figsize=3)
ytPlot = list_plot(YtData, rgbcolor='red', figsize=3)
# プロット表示
Table2Html([["政府支出", "消費"], [_to_png(gtPlot), _to_png(ctPlot)],
["投資", "所得"], [ _to_png(itPlot), _to_png(ytPlot)]])
政府支出 | 消費 |
投資 | 所得 |
経済データを表現するモデルとして以下のような関係をもつ数学モデルを作ります。
矩形はモデルの変数を表し、 Y:所得、C:消費、I:投資、G:政府支出です。 矢印の方向は影響を与える向きを表します。 消費は自分自身へ矢印があり、これは前年度の消費が今年度の 消費に影響を与えていることを表しています。
このモデルを連立方程式で表すと、以下のようになります。 $$ \left\{ \begin{array}{l c l} C_t & = & a_0 + a_1 Y_t + a_2 C_{t-1} \\ I_t & = & b_0 + b_1 Y_t \\ Y_t & = & C_t + I_t + G_t \\ \end{array} \right. $$
モデルの作成手順は、以下のようにします。
連立方程式のCt, Itの係数$a_0, a_1, a_2, b_0, b_1$の値を回帰分析 (find_fit関数)を使って求めます。
教師用データとして、CtList, YtList, GtListには、1966年から1984年のデータをセットし、 Ct1Listには、1年ずらしたCtの値をセットします。
# Ctの計算には前年度のCtであるCt-1を使うため1966年から1984年のデータを作成
CtList = CtData[1:20]
Ct1List= CtData[0:19]
YtList = YtData[1:20]
GtList = GtData[1:20]
ItList = ItData[1:20]
最初に、消費Ctの式$C_t = a_0 + a_1 Y_t + a_2 C_{t-1}$ の係数$a_0, a_1, a_2$を求めてみましょう。
find_fit関数の引数は以下のように与えます。
find_fit(data, model, options) data: 変数1の値, 変数2の値, ... , 変数nの値, 関数の値をタプルとするリストをセット model: model(変数1の値, 変数2の値, ... , 変数nの値)の引数を持つ関数をセット options: solution_dict=Trueを指定すると係数名をキーとする辞書が戻されます
最初に、変数Yt, Ct, Ct1と係数a0, a1, a2を定義します。 次に、消費のモデルとしてCtModelシンボリック関数を定義します。
データの形式は、消費のモデルCtModelの引数がYt, Ct1であり、 モデルの表す値がCtですから、Yt, Ct1, Ctのタプルのリストを渡します。
各年度のYt, Ct1, Ctのタプルは、zip関数を使って作成します。
# 各年度のYt, Ct1, Ctをタプルにまとめたリストを作成
data = zip(YtList, Ct1List, CtList)
# モデル関数と変数を定義
(Yt, Ct, Ct1, a0, a1, a2) = var('Yt Ct Ct1 a0 a1 a2')
CtModel(Yt, Ct1) = a0 + a1*Yt + a2*Ct1
# 最適な解のa0, a1, a2を求める
CtFit = find_fit(data, CtModel, solution_dict=True); CtFit
{a1: 0.21857976971146675, a2: 0.5926819161790804, a0: 7518.309603737444}
消費と同様に、投資Itの式$I_t = b_0 + b_1 Y_t$ の係数$b_0, b_1$を求めます。
新たに変数Yt, b0, b1を定義し、投資のモデルとしてItModelシンボリック関数を定義します。
データの形式は、投資のモデルItModelの引数がYtであり、 モデルの表す値がItですから、Yt, Itのタプルのリストを渡します。
# 同様にItに対するb0, b1を求める
data = zip(YtList, ItList)
(Yt, b0, b1) = var('Yt b0 b1')
ItModel(Yt) = b0 + b1*Yt
ItFit = find_fit(data, ItModel, solution_dict=True); ItFit
{b0: 311.21923398160885, b1: 0.15818655082721944}
係数a0, a1, b2, b0, b1が決まったので、solve関数を使って連立方程式 を解きます。
係数を入力して式を定義する代わりに、
CtEq = (Ct == CtModel(Yt, Ct1)).subs(CtFit)のようにsubs関数を使ってCt == a0 + a1*Yt + a2*Ct1のa0, a1, a2を代入しています。 これで、モデルを変更しても再計算が楽にできます。 解の結果、Ct, It, YtはGtとCt1からなる式に変換されています。
経済モデルから前年度の消費と今年度の政府支出によって、今年度の消費、投資、所得を求める式を得ることができました。
# 連立方程式をCt, It, Ytに対して解く
(Gt, It) = var('Gt It')
CtEq = (Ct == CtModel(Yt, Ct1)).subs(CtFit)
ItEq = (It == ItModel(Yt)).subs(ItFit)
YtEq = (Yt == Ct + It + Gt)
eqn = [CtEq, ItEq, YtEq]; eqn
[Ct == 0.5926819161790804*Ct1 + 0.21857976971146675*Yt + 7518.309603737444, It == 0.15818655082721944*Yt + 311.21923398160885, Yt == Ct + Gt + It]
sol = solve(eqn, [Ct, It, Yt], solution_dict=True); sol
[{Yt: 1760421695327231515898/1851168494654738992935*Ct1 + 1665464251735955/1037973413620683*Gt + 27161739944082251799229948075/2162085545220791309256249, Ct: 7409733296710051049024/9255842473273694964675*Ct1 + 364036792607125/1037973413620683*Gt + 22192235380675639267030739855/2162085545220791309256249, It: 1392375179926106530466/9255842473273694964675*Ct1 + 263454045508147/1037973413620683*Gt + 4969504563406612532199208220/2162085545220791309256249}]
計算結果と実データを比較するために、zip関数を使って前年度消費と政府支出をタプルとするリストを作成します。
# 入力データをセット
data = zip(Ct1List, GtList)
連立方程式から消費Ct、投資It、所得Ytを計算する式を取り出し、 前年度消費Ct1と今年度政府支出を引数とする関数ctFunc, itFunc, ytFuncを定義します。
ctFunc(Ct1, Gt) = sol[0][Ct]; show(ctFunc ) # 消費計算関数
itFunc(Ct1, Gt) = sol[0][It]; show(itFunc) # 投資計算関数
ytFunc(Ct1, Gt) = sol[0][Yt]; show(ytFunc) # 所得計算関数
求めた関数ctFunc, itFunc, ytFuncを使って教師用データの消費、投資、所得をシミュレーション してみましょう。
dataの各タプルに対し、リスト内包を使って関数から計算結果のリストを作成します。
# 消費のシミュレーション結果
calCtList = [ctFunc(Ct1, Gt).n() for (Ct1, Gt) in data]
# 投資のシミュレーション結果
calItList = [itFunc(Ct1, Gt) for (Ct1, Gt) in data]
# 所得のシミュレーション結果
calYtList = [ytFunc(Ct1, Gt) for (Ct1, Gt) in data]
list_plotを使って教師用データに対するシミュレーション結果(青い線)と実データ(赤い点)をプロットします。 単純なモデルの割には消費と所得に対しては、シミュレーション結果と実データが合っています。 投資については、所得Ytのみが影響するモデルとなっているため、実データの変動をうまく表現できていません。
# 計算値(青)と実測値(赤)のプロット
gtPlot = list_plot(GtList, rgbcolor='red', figsize=3)
calCtPlot = list_plot(calCtList, plotjoined=true, figsize=3)
ctPlot = list_plot(CtList, rgbcolor='red', figsize=3)
calItPlot = list_plot(calItList, plotjoined=true, figsize=3)
itPlot = list_plot(ItList, rgbcolor='red', figsize=3)
calYtPlot = list_plot(calYtList, plotjoined=true, figsize=3)
ytPlot = list_plot(YtList, rgbcolor='red', figsize=3)
# プロット表示
Table2Html([["政府支出", "消費"], [_to_png(gtPlot), _to_png(calCtPlot + ctPlot)],
["投資", "所得"], [_to_png(calItPlot + itPlot), _to_png(calYtPlot + ytPlot)]])
政府支出 | 消費 |
投資 | 所得 |
同様に検証用データに対してシミュレーションを行ってみましょう。
消費、所得については、モデルはよく表現できていますが、 投資については急激な増加をうまく表現できていません。
# 検証用データ
valCtList = [calCtList[18]]
valItList = [calItList[18]]
valYtList = [calYtList[18]]
Ct1List = CtData[0:24]
GtList = GtData[1:25]
CtList = CtData[1:25]
for i in range(19, 24):
valCtList.append(ctFunc(Ct1List[i], GtList[i]))
valItList.append(itFunc(Ct1List[i], GtList[i]))
valYtList.append(ytFunc(Ct1List[i], GtList[i]))
# 教師用+検証用の実測値(赤)
ctPlot = list_plot(CtData[1:24], rgbcolor='red', figsize=3)
itPlot = list_plot(ItData[1:25], rgbcolor='red', figsize=3)
ytPlot = list_plot(YtData[1:25], rgbcolor='red', figsize=3)
gtPlot = list_plot(GtData[1:25], rgbcolor='red', figsize=3)
# 計算値(青)、検証値(灰)
valCtPlot = list_plot(zip(range(18,24), valCtList), plotjoined=true, rgbcolor ='gray', figsize=3)
valItPlot = list_plot(zip(range(18,24), valItList), plotjoined=true, rgbcolor ='gray', figsize=3)
valYtPlot = list_plot(zip(range(18,24), valYtList), plotjoined=true, rgbcolor ='gray', figsize=3)
# プロット
ctPlt = (calCtPlot + ctPlot +valCtPlot)
itPlt = (calItPlot + itPlot + valItPlot)
ytPlt = (calYtPlot + ytPlot + valYtPlot)
Table2Html([["政府支出", "消費"], [_to_png(gtPlot), _to_png(ctPlt)],
["投資", "所得"], [_to_png(itPlt), _to_png(ytPlt)]])
政府支出 | 消費 |
投資 | 所得 |
シミュレーションの結果から、モデルは消費をうまく表現していることが確認でます。 このことから、もし政府支出が予測できたら今年度度消費の値から来年度の消費、投資、所得 を計算することができます。
問題を簡単にするために、政府支出Gtを$G_t(x) = c_0 + c_1 x$として回帰分析をします。
# 1985年から1989年のデータを予測
var('x c0 c1')
data = zip(range(20), GtList[0:20])
# 直線回帰から政府支出のモデルGtの係数を求める
GtModel(x) = c0 + c1*x
GtFit = find_fit(data, GtModel, solution_dict=True); GtFit
{c0: 36476.85006850687, c1: 1837.6999989361932}
直線回帰で求めた政府支出と実データをプロットすると以下のようになります。
gtPlot = list_plot(GtList, rgbcolor='red', figsize=3)
gtFunc(x) = GtModel.subs(GtFit)
calGtPlot = plot(gtFunc, [x, 0, 19], figsize=3)
(calGtPlot + gtPlot).show()
ちょっと乱暴な遊びですが、 政府支出関数gtFuncを使って、1967年から1989年まで政府支出を求め、前年度の消費Ct1List の値とgtFuncの値から消費、投資、所得を順番に計算してみましょう。
# 予測
predCt1List =[ Ct1List[0]] + range(23)
predCtList = [calCtList[0]]
predItList = [calItList[0]]
predYtList = [calYtList[0]]
for i in range(1, 24):
predCt1List[i] = ctFunc(predCt1List[i-1], gtFunc(i-1))
predCtList.append(ctFunc(predCt1List[i], gtFunc(i)))
predItList.append(itFunc(predCt1List[i], gtFunc(i)))
predYtList.append(ytFunc(predCt1List[i], gtFunc(i)))
政府支出の乱暴な予測にも関わらず、予測値(緑)は先のシミュレーション結果と ほぼ同じ傾向を示しています。
このようにシミュレーションは、未来の予測にも活用できることが理解して頂けたでしょうか。
# 計算値(青)、予測値(緑)と実測値(赤)
predCtPlot = list_plot(zip(range(24), predCtList), plotjoined=true, rgbcolor ='green', linestyle='dashed', figsize=3)
predItPlot = list_plot(zip(range(24), predItList), plotjoined=true, rgbcolor ='green', linestyle='dashed', figsize=3)
predYtPlot = list_plot(zip(range(24), predYtList), plotjoined=true, rgbcolor ='green', linestyle='dashed', figsize=3)
calGtPlot = plot(gtFunc, [x, 0, 23], figsize=3)
# プロット
ctPlt = (calCtPlot + predCtPlot + ctPlot + valCtPlot)
itPlt = (calItPlot + predItPlot + itPlot + valItPlot)
ytPlt = (calYtPlot + predYtPlot + ytPlot + valYtPlot)
Table2Html([["政府支出", "消費"], [_to_png(calGtPlot + gtPlot), _to_png(ctPlt)],
["投資", "所得"], [_to_png(itPlt), _to_png(ytPlt)]])
政府支出 | 消費 |
投資 | 所得 |