{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "(chap:9-solow)=\n", "# ソロー・モデル" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<div name=\"html-admonition\" style=\"font-size: 0.8em\">\n", "<input type=\"button\" onclick=\"location.href='https://translate.google.com/translate?hl=&sl=ja&tl=en&u='+window.location;\" value=\"Google translation\" style=\"color:#ffffff;background-color:#008080; height:25px\" onmouseover=\"this.style.background='#99ccff'\" onmouseout=\"this.style.background='#008080'\"/> in English or the language of your choice.\n", "</div><br>" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import japanize_matplotlib\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import py4macro\n", "import statsmodels.formula.api as smf\n", "\n", "# numpy v1の表示を使用\n", "np.set_printoptions(legacy='1.21')\n", "# 警告メッセージを非表示\n", "import warnings\n", "warnings.filterwarnings(\"ignore\")" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "## はじめに" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "前章では差分方程式について説明し,簡単な経済モデルを使いコードの書き方を説明した。本章では,差分方程式の応用となるソロー・モデルを考える。ソロー・モデルは1987年にノーベル経済学賞を受賞した[Robert M. Solow](https://www.nobelprize.org/prizes/economic-sciences/1987/press-release/)によって考案された経済成長モデルであり,マクロ経済学の代表的な理論モデルの一つである。今でも盛んに研究が続く経済成長のバックボーン的な存在である。モデルの説明の後,`Python`を使い動学的な特徴を明らかにし,線形近似を使った安定性の確認もおこなう。また理論的な予測がデータと整合性があるかについてもPenn World Tableを使って検討する。本章の内容は次章で議論する所得収斂の分析の基礎となる。" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "## モデルの説明" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "ここではモデルの具体的な説明については教科書に譲るとして,簡単にモデルを紹介し,重要な式をまとめることにする。\n", "\n", "<記号>\n", "* 産出量:$Y_t$\n", "* 消費量:$C_t$\n", "* 投資量:$I_t$\n", "* 資本ストック:$K_t$\n", "* 労働:$L_t$\n", "* 貯蓄率(一定な外生変数):$0<s<1$\n", "* 労働人口増加率(一定な外生変数):$n\\equiv\\dfrac{L_{t+1}}{L_t}-1\\geq 0$\n", "* 資本減耗率(一定な外生変数):$0<d<1$\n", "* 生産性(一定な外生変数):$A>0$\n", "\n", "<一人当たりの変数>\n", "* 一人当たり産出量:$y_t\\equiv\\dfrac{Y_t}{L_t}$\n", "* 一人当たり消費量:$c_t\\equiv\\dfrac{C_t}{L_t}$\n", "* 一人当たり投資量:$i_t\\equiv\\dfrac{I_t}{L_t}$\n", "* 一人当たり資本ストック:$k_t\\equiv\\dfrac{K_t}{L_t}$" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "全ての市場は完全競争である閉鎖経済を考えよう。この経済には一種類の財(ニューメレール財)しかなく,消費・貯蓄・投資に使われる。財は次の生産関数に従って生産される。\n", "\n", "$$\n", "Y_t=AK_t^aL_t^{1-a},\\quad 0<a<1\n", "$$ (eq:8-production_level)\n", "\n", "両辺を$L_t$で割ると一人当たりの変数で表した生産関数となる。\n", "\n", "$$\n", "y_t=Ak_t^a\n", "$$ (eq:8-production)\n", "\n", "消費者は所得の割合$s$を貯蓄するが,このモデルの中で消費者の役割はこれだけであり,残り全ては生産側で決定される。貯蓄は$sY_t$であり投資$I_t$と等しくなる。\n", "\n", "$$\n", "sY_t=I_t\n", "$$ (eq:8-syi)" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "$t$期の投資により$t+1$期の資本ストックは増加するが,毎期ごと資本は$d$の率で減耗する。即ち,投資と資本ストックには次の関係が成立する。\n", "\n", "$$\n", "K_{t+1}-K_{t}=I_t-dK_t\n", "$$ (eq:8-kk)\n", "\n", "ここで左辺は資本ストックの変化であり,右辺は純投資である。$I_t$は粗投資,$dK_t$は減耗した資本である。式[](eq:8-syi),[](eq:8-kk),[](eq:8-production)を使うと資本の蓄積方程式が導出できる。\n", "\n", "$$\n", "K_{t+1} = sAK_t^aL^{1-a} + (1-d)K_t\n", "$$ (eq:8-kkdot)\n", "\n", "両辺を$L_t$で割ることで一人当たりの変数で表すことができる。右辺は単純に一人当たりの変数に直し,左辺は次のように書き換えることに注意しよう。\n", "\n", "$$\n", "\\frac{K_{t+1}}{L_t}=\\frac{K_{t+1}}{L_{t+1}}\\frac{L_{t+1}}{L_t}\n", "=k_{t+1}(1+n)\n", "$$\n", "\n", "従って,$t+1$期の一人当たりの資本ストックを決定する式は次式で与えられる。\n", "\n", "$$\n", "k_{t+1} = \\frac{sAk_t^a + (1-d)k_t}{1+n}\n", "$$ (eq:8-kdot)\n", "\n", "この式は非線形の差分方程式だが,前章でも述べたように,考え方は線形差分方程式と同じであり,数値計算のための`Python`コードに関しては大きな違いはない。また式[](eq:8-kdot)を資本ストックの成長率を示す式に書き換えることもできる。\n", "\n", "$$\n", "\\frac{k_{t+1}}{k_t}-1 = \\frac{sAk_t^{-(1-a)}-(n+d)}{1+n}\n", "$$ (eq:8-kgrowth)\n", "\n", "この式から資本が蓄積され$k_t$が増加すると,その成長率は減少していくことが分かる。" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "産出量の動学は生産関数[](eq:8-production)を使うことによって$y_t$の動きを確認できる。例えば,産出量の成長率を考えてみよう。式[](eq:8-production)を使うと\n", "\n", "$$\n", "\\frac{y_{t+1}}{y_t}-1\n", "=\\left(\\frac{k_{t+1}}{k_t}\\right)^{\\alpha}-1\n", "$$ (eq:8-ygrowth)\n", "\n", "となり,一人当たり資本ストックの成長率と同じような動きをすることが分かると思う。" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "次に定常状態を考えよう。定常状態では資本ストックは一定なり,資本の成長率である式[](eq:8-kgrowth)の右辺はゼロになる。\n", "定常値は次のように確認することができる。\n", "\n", "$$\n", "\\begin{align*}\n", "\\frac{k_*}{k_*}-1 \n", "&=\\frac{sAk_*^{-(1-a)} - (n+d)}{1+n} \\\\\n", "&\\Downarrow \\\\\n", "k_*\n", "&=\\left(\n", " \\frac{As}{n+d}\n", " \\right)^{\\frac{1}{1-a}}\n", "\\end{align*}\n", "$$ (eq:8-kss)\n", "\n", "この値を生産関数[](eq:8-production)に代入することにより一人当たりGDPの定常値を求めることができる。\n", "\n", "$$\n", "y_*=Ak_*^{a}\n", "$$ (eq:8-yss)" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "{numref}`fig:8-solow`は資本ストックの動学的均衡を示している。\n", "\n", "```{figure} /images/solow.jpeg\n", "---\n", "scale: 30%\n", "name: fig:8-solow\n", "---\n", "一人当たり資本ストックの動学\n", "```" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "## 動学" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "差分方程式[](eq:8-kdot)を使って資本ストックの変化をプロットするが,以前と同じように`DataFrame`を生成する関数を定義しよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "def solow_model(k0, A=10, a=0.3, s=0.3, n=0.02, d=0.05, T=100):\n", " \"\"\"引数\n", " k0: 資本の初期値\n", " A: 生産性\n", " a: 資本の所得比率 (a<1)\n", " s: 貯蓄率 (s<1)\n", " n: 労働人口成長率(%)\n", " d: 資本減耗率 (d<1)\n", " T: ループによる計算回数\n", " 戻り値\n", " 資本と産出量からなるDataFrame\"\"\"\n", " \n", " k = k0\n", " y = A * k0**a\n", " \n", " k_lst = [k]\n", " y_lst = [y]\n", "\n", " for t in range(T):\n", " \n", " k = ( s * A * k**a + (1-d) * k )/( 1+n )\n", " y = A * k**a\n", "\n", " k_lst.append(k)\n", " y_lst.append(y)\n", "\n", " # DataFrameの作成\n", " dic = {'capital':k_lst, 'output':y_lst}\n", " df = pd.DataFrame(dic)\n", " \n", " return df " ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "引数に使うパラーメータには次の値を使ってプロットしてみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "df = solow_model(k0=200)\n", "df.plot(subplots=True)\n", "pass" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "異なる初期値を使って資本の変化をプロットしてみる。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "initial_lst = range(100,300,10) # 1\n", "\n", "ax = pd.DataFrame({'capital':[],\n", " 'output':[]}).plot(legend=False) # 2\n", "\n", "for i in initial_lst: # 3\n", " \n", " solow_model(k0=i).plot(y='capital', legend=False, ax=ax)\n", " \n", "ax.set(title='ソロー・モデルの移行過程', # 4\n", " xlabel='ループの回数',\n", " ylabel='一人当たり資本ストック')\n", "pass" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "````{admonition} コードの説明\n", ":class: dropdown\n", "\n", "* `#1`:`range(100,300,10)`は100から300-1=299までの間の数を10間隔で生成する。100,110,120,$cdots$,290となる。\n", "* `#2`:空の`DataFrame`を使って空の軸を作成し,`ax`に割り当てる。\n", "* `#3`:`initial_list`に対して`for`ループを設定する。一回のループごとに以下をおこなう。\n", " * `i`は`k0`の引数に使う値になる。\n", " * `.plot()`を使い`ax`に図をプロットする。これにより図が重ねて描かれる。\n", "* `#4`:`ax`のメソッド`set()`を使い,引数を使い以下を追加する。\n", " * `title`:図のタイトル\n", " * `xlabel`:横軸のラベル\n", " * `ylabel`:縦軸のラベル\n", " * この3行を次のように書いても同じ結果となる。\n", " ```\n", " ax.set_title('ソロー・モデルの移行過程')\n", " ax.set_xlabel('ループの回数')\n", " ax.set_ylabel('一人当たり資本ストック')\n", " ```\n", " この3つを`.set()`でまとめて書いたのが上のコードである。3つに分けて書く利点はフォントの大きさを指定できることだろう。\n", "````" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "図から初期値に関わらず定常値に収束していることが分かる。即ち,定常状態である長期均衡は安定的である。" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "## 定常状態での変数の値" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "次に定常状態での変数の値を計算してみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "def calculate_steady_state(A=10, a=0.3, s=0.3, n=0.02, d=0.05):\n", " \n", " k_ss = ( s * A / (n+d) )**( 1/(1-a) ) \n", " y_ss = A * k_ss**( a/(1-a) ) \n", " \n", " return k_ss, y_ss" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ss = calculate_steady_state()\n", "\n", "print(f'定常状態での資本ストック:{ss[0]:.1f}'\n", " f'\\n定常状態での産出量: {ss[1]:.1f}')" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "## 線形近似" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "### 説明" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "{numref}`fig:8-solow`は,定常状態は安定的であることを示している。またシミュレーションの結果からも定常状態の安定性が確認できる。次に,線形近似を使って解析的に安定性を確認してみることにする。また線形近似は真の値からの乖離が発生するが,その乖離がどの程度のものかをコードを使って計算することにする。\n", "\n", "<テイラー展開による1次線形近似>\n", "* 関数$z=f(x)$を$x_*$でテイラー展開すると次式となる。\n", "\n", " $$\n", " z=f(x^*)+\\left.\\frac{df}{dx}\\right|_{x=x_*}(x-x_*)\n", " $$" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "ソロー・モデルの式に当てはめると次のような対応関係にある。\n", "* $z\\;\\Rightarrow\\;k_{t+1}$\n", "* $f(x)\\;\\Rightarrow\\;\\dfrac{Ask_{t}^{\\alpha}+(1-d)k_t}{1+n}$\n", "* $x^*\\;\\Rightarrow\\;k^*$\n", "\n", "公式に従って計算してみよう。\n", "\n", "$$\n", "\\begin{align*}\n", "k_{t+1}\n", "&=\\frac{Ask_{*}^{\\alpha}+(1-d)k_*}{1+n}\n", "+\\frac{1}{1+n}\\left[\\frac{Asa}{k_t^{1-\\alpha}}+(1-d)\\right]_{k_t=k_*}(k_t-k_*) \\\\\n", "&=k_{*}\n", "+\\frac{1}{1+n}\\left[\\frac{Asa}{k_*^{1-\\alpha}}+(1-d)\\right](k_t-k_*) \\\\\n", "&=k_*+\\frac{1}{1+n}\\left[\\frac{Asa}{As/(n+d)}+(1-d)\\right](k_t-k_*) \\\\\n", "&=k_*+\\frac{a(n+d)+1-d-n+n}{1+n}(k_t-k_*) \\\\\n", "&=k_*+\\frac{1+n-(1-a)(n+d)}{1+n}(k_t-k_*) \\\\\n", "&=(1-\\lambda) k_t + \\lambda k_*\n", "\\end{align*}\n", "$$ (eq:8-kapprox)\n", "\n", "ここで\n", "\n", "$$\n", "\\lambda\\equiv \\frac{(1-a)(n+d)}{1+n}\n", "$$ (eq:8-lambda)" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "3行目は定常状態の式[](eq:8-kdot)と式[](eq:8-kss)を使っている。式[](eq:8-kapprox)は$k_{t+1}$と$k_t$の線形差分方程式になっており,$k_t$の係数は\n", "\n", "$$\n", "0<1-\\lambda<1\n", "\\quad\\because\n", "0<a,d<1\n", "$$ (eq:8-coef_of_kt)\n", "\n", "が成立する。{numref}`fig:8-solow`の赤い直線が式[](eq:8-kapprox)である。従って,初期値$k_0>0$からスタートする経済は必ず長期的均衡に収束することがわかる。\n", "\n", "式[](eq:8-lambda)は$k_t$の係数だが,その裏にあるメカニズムを考えてみよう。特に,$a$の役割を考える。$a$は資本の所得比率であり,目安の値は1/3である。そしてソロー・モデルにおける重要な役割が**資本の限界生産性の逓減**を決定することである。この効果により資本ストックが増加する毎に産出量も増加するがその増加自体が減少する。この効果により,{numref}`fig:8-solow`の曲線は凹関数になっており,生産関数[](eq:8-production)の場合は必ず45度線と交差することになる。即ち,資本の限界生産性の逓減こそが$k_t$が一定になる定常状態に経済が収束す理由なのである。この点がソロー・モデルの一番重要なメカニズムとなる。\n", "\n", "ここで$a$が上昇したとしよう。そうなると資本の限界生産性の逓減の効果は弱くなり,資本ストックが増加しても産出量の増加自体の減少は小さくなる。また式[](eq:8-kss)が示すように定常状態での資本ストックはより大きくなる。これは{numref}`fig:8-solow`で曲線が上方シフトしている考えると良いだろう。" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{admonition} 内生的成長\n", ":class: note\n", "更に$a$を上昇させて$a=1$になるとどうなるのだろう。この場合,資本の限界生産性は逓減せず一定となる。そして$k_t$の係数である式[](eq:8-coef_of_kt)は1になってしまい,$k_t$が一定になる定常状態が存在しなくなる。$a=1$となる極限の状態を内生的成長と呼ぶ。ここでは立ち入った議論はしないが,内生的成長の典型的な生産関数は次式となり,\n", "\n", "$$y_t=Ak_t$$\n", "\n", "この生産関数に基づくモデルは$AK$モデルと呼ばれる。資本の限界生産性は$A$で一定になることが分かると思う。\n", "```" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "### $\\lambda$の解釈" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "上の議論から$\\lambda$が定常状態の安定性を決定することが分かったが,$\\lambda$の値はどのように解釈できるだろうか。例えば,$\\lambda$が大きい場合と小さい場合では何が違うのだろうか。次式は式[](eq:8-kapprox)の最後の等号を少し書き換えたものである。\n", "\n", "$$\n", "k_*-k_{t+1}=(1-\\lambda)(k_*-k_t)\n", "$$ (eq:8-approx_lastline)\n", "\n", "左辺は$t+1$期において定常状態までの残りの「距離」であり,右辺の$k_*-k_t$は$t$においての定常状態までの残りの「距離」である。後者を次の様に定義し\n", "\n", "$$z_t\\equiv k_*-k_t$$\n", "\n", "式[](eq:8-approx_lastline)を整理すると次式となる。\n", "\n", "$$\n", "\\frac{z_{t+1}-z_t}{z_t}=-\\lambda\n", "$$ (eq:8-kspeed)\n", "\n", "左辺は$t$期と$t+1$期において定常状態までの「距離」が何%減少したかを示す**資本ストックの収束速度**である。このモデルの中での収束速度の決定要因は資本の所得比率$\\alpha$,労働人口増加率$n$と資本の減耗率$d$ということである。" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "ここでは$a$の役割に着目し,なぜ$a$の上昇は収束速度の減少をもたらすのかを直感的に考えてみよう。この点を理解するために,まず$a$は資本の限界生産性の逓減を決定するパラーメータであることを思い出そう。$a$が上昇するとその効果は弱まる。即ち,資本ストックが1単位増加すると産出量は増え,その増加分が減少するのが「逓減」であるが,その減少が小さくなるのである。これにより(上で説明したように)$k_t$が一定となる定常状態は増加することになる。重要な点は,定常状態の増加の意味である。定常状態はマラソンのゴールの様なものである。トップランナーはゴールすると走るのを止め,後続ランナーはトップランナーとの「距離」を縮めることができる。定常状態の増加は,ゴールが遠くなることと同じである。ゴールが遠のくとトップランナーは走り続けるわけだから,それだけ距離を縮めることが難しくなり収束速度が減少することになる。極端なケースとして$a=1$の場合,$k_t$が一定になる定常状態は存在せず,ゴールがない状態が永遠に続いており,永遠に収束しないということである。言い換えると,資本の限界生産性の逓減($a<1$)こそが「距離」を縮めキャッチアップを可能にするメカニズムなのだ。\n", "\n", "労働人口増加率$n$と資本の減耗率$d$の上昇は収束速度を速くする。式[](eq:8-kss)から分かる様に,$n$もしくは$d$の上昇は定常状態を減少させる。即ち,ゴールはより近くになるということだ。\n", "\n", "これである程度キャッチアップのメカニズムが分かったと思うが,今までの議論で足りないものが2点あるので,それらについて簡単に言及する。第一に,ここで考えたソロー・モデルには技術進歩が抜けている(一定な$A$を仮定した)。この点を導入してこそソロー・モデルのフルバージョンであり,その場合の労働効率1単位当たり資本ストック($K_t/(A_tL_t)$)の収束速度は次の式で与えられる。\n", "\n", "$$\n", "\\lambda\\equiv \\frac{(1-a)(g+n+d+ng)}{(1+n)(1+g)}\n", "$$ (eq:8-lambda_g)\n", "\n", "ここで$g$は技術進歩率である。ソロー・モデルでは4つの変数が収束速度の決定要因になるる。$g=0$の場合,式[](eq:8-lambda)と同じになることが確認できる。第二に,式[](eq:8-lambda)は資本ストックの収束速度であり一人当たりGDPの収束速度と異なるのではないかという疑問である。実は同じである。これはコブ・ダグラス生産関数[](eq:8-production)を仮定しているからであり,対数の近似を使えば簡単に示すことができる。式[](eq:8-approx_lastline)を次のように書き直そう。\n", "\n", "$$\n", "\\frac{k_{t+1}}{k_*}-1=(1-\\lambda)\\left(\\frac{k_t}{k_*}-1\\right)\n", "$$ (eq:8-ks_rewrite)\n", "\n", "ここで$\\log(1+x-1)\\approx x-1$の近似を使い左辺を次のように書き換える。\n", "\n", "$$\n", "\\frac{k_{t+1}}{k_*}-1\n", "\\approx\\log\\left(\\frac{k_{t+1}}{k_*}\\right)\n", "=\\log\\left(\\frac{y_{t+1}}{y_*}\\right)^{\\frac{1}{\\alpha}}\n", "=\\frac{1}{\\alpha}\\left(\\frac{y_{t+1}}{y_*}-1\\right)\n", "$$\n", "\n", "同様に$\\dfrac{k_{t}}{k_*}-1$もこの形に書き換えることができる。後はこの関係を使うことにより,式[](eq:8-ks_rewrite)を整理すると次式となる。\n", "\n", "$$\n", "y_*-y_{t+1}=(1-\\lambda)(y_*-y_t)\n", "$$ (eq:8-y_difference_eq)\n", "\n", "式[](eq:8-approx_lastline)と同じ形になっているので所得の収束速度も式[](eq:8-kspeed)と同じである。" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "### 線形近似による誤差" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "次に関数`solow_model()`を修正して線形近似の誤差を確かめてみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "def solow_model_approx(k0, A=10, a=0.3, s=0.3, n=0.02, d=0.05, T=20):\n", " \"\"\"引数\n", " k0: 資本の初期値\n", " A: 生産性\n", " a: 資本の所得比率 (a<1)\n", " s: 貯蓄率 (s<1)\n", " n: 労働人口成長率(n>=0)\n", " d: 資本減耗率 (d<1)\n", " T: ループによる計算回数\n", " 戻り値\n", " 線形近似モデルを使い計算した資本と産出量からなるDataFrame\"\"\"\n", " \n", " k = k0\n", " y = A * k0**a\n", " \n", " k_lst = [k]\n", " y_lst = [y]\n", "\n", " # 定常状態\n", " k_ss = ( s*A / (n+d) )**( 1 / (1-a) ) \n", " \n", " for t in range(T):\n", " \n", " lamb = 1 - (1-a) * (n+d) / (1+n) # lambda\n", " k = lamb*k + (1-lamb) * k_ss # 線形近似\n", " y = A * k**a\n", "\n", " k_lst.append(k)\n", " y_lst.append(y)\n", "\n", " # DataFrameの作成\n", " dic = {'capital':k_lst, 'output':y_lst}\n", " df = pd.DataFrame(dic)\n", " \n", " return df" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "近似誤差を計算するために,上と同じ数値でシミュレーションをおこなう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "df_approx = solow_model_approx(k0=200, T=150)" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "非線形のモデル[](eq:8-kdot)と線形近似のモデル[](eq:8-kapprox)で計算された資本ストックを重ねて図示してみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ax = df_approx.plot(y='capital', label='線形近似モデル')\n", "df.plot(y='capital', label='ソロー・モデル', ax=ax)\n", "pass" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "`df_approx`が図示され、その上に`df`が重ねて表示されるが、殆ど同じのように見える。誤差を%で計算し図示してみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "( 100*( 1-df_approx['capital']/df['capital'] ) ).plot(marker='.')\n", "pass" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "初期の資本ストック$k_0$は同じなので誤差はゼロであり,$t=1$から線形近似の誤差が現れることになる。誤差は単調ではない。{numref}`fig:8-solow`の図が示しているように,階段のような形で増加していくためであり,その階段お大きさや進み具合が異なるためである。線形近似の値は大き過ぎるため負の値になっているが、誤差は大きくても約0.02%であり、定常状態に近づくにつれて誤差はゼロに近づいている。もちろん,誤差の値は初期値が定常値から離れればそれだけ大きくなっていく。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 長期均衡の予測" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true }, "source": [ "### 説明" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "この節では長期均衡(定常状態)に焦点を当て,理論的な予測のデータとの整合性をチェックする。まず定常状態の特徴をまとめよう。式[](eq:8-kss)と[](eq:8-yss)を使いうと定常状態での一人当たり資本ストックとGDPは次式で与えれる。\n", "\n", "$$\n", "k_*=\n", "\\left(\n", " \\frac{sA}{n+d}\n", "\\right)^{\\frac{1}{1-a}},\n", "\\quad\n", "y_*=Ak_*^a\n", "$$\n", "\n", "この2つをそれぞれ試すこともできるが,同時に捉えるために2つの式の比率を考える。\n", "\n", "$$\n", "\\frac{k_*}{y_*}=\\frac{s}{n+d}\n", "=\\left.\\frac{K_t/L_t}{Y_t/L_t}\\right|_{\\text{定常状態}}\n", "=\\left.\\frac{K_t}{Y_t}\\right|_{\\text{定常状態}}\n", "$$ (eq:8-kyratio)\n", "\n", "この値は資本ストック対GDP比と等しいく,次のことが分かる。\n", "* 貯蓄率$s$の上昇は資本ストック対GDP比を増加させる。。\n", "* 労働人口成長率$n$の上昇は資本ストック対GDP比を減少させる。\n", "* 資本減耗率$d$の上昇は資本ストック対GDP比を減少させる。\n", "\n", "この3つの予測が成立するか確かめるために`py4macro`モジュールに含まれるPenn World Dataの次の変数を使う。\n", "* `cgdpo`:GDP(2019年;生産側)\n", "* `cn`:物的資本ストック(2019年)\n", "* `csh_i`:対GDP比資本形成の比率\n", " * 投資の対GDP比である。\n", " * 貯蓄率$s$の代わりに使う。\n", " * 1960年〜2019年の平均を使う。\n", "* `emp`:雇用者数\n", " * 労働人口の代わりに使う。\n", " * 1960年〜2019年の平均成長率$n$の計算に使う。\n", "* `delta`:資本ストックの年平均減耗率\n", " * 1960年〜2019年の平均を使う。" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "tags": [ "remove-cell" ] }, "source": [ "### データ" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "(sec:8-data)=\n", "### データ" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "1960年以降のデータを`pwt`に割り当てる。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "pwt = py4macro.data('pwt').query('year >= 1960')" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "#### 貯蓄率" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "1960年から2019年までの国別の貯蓄率の平均を計算するが必要がある。[ここで説明している](https://py4basics.github.io/3_Pandas.html#id33)`DataFrame`のメソッド`.groupby()`を使うのが最も簡単な計算方法だろう。ここでは異なる方法として`DataFrame`のメソッド`.pivot()`を紹介する。`.pivot()`はデータを整形する上で非常に便利なメソッドなので知って損はないだろう。\n", "\n", "`.pivot()`は,元の`DataFrame`から列を選び,その列から新たな`DataFrame`を作成する便利なメソッドである。実際にコードを実行して説明しよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true, "tags": [ "output_scroll" ] }, "outputs": [], "source": [ "saving = pwt.pivot(index='year', columns='country', values='csh_i')\n", "saving.head()" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{admonition} コードの説明\n", ":class: dropdown\n", "\n", "`pwt`の3つの列`year`,`country`,`csh_i`を使って新たな`DataFrame`を作成し`saving`に割り当てている。引数は次の役割をする。\n", "* `index`:新たな`DataFrame`の**行ラベル**を指定する。\n", " * コードでは`year`が指定され行ラベルになっている。\n", "* `columns`:新たな`DataFrame`の**列ラベル**を指定する。\n", " * コードでは`country`が指定され列ラベルになっている。\n", "* `values`:新たな`DataFrame`の**値**を指定する。\n", " * コードでは`csh_i`が指定され,その値で`DataFrame`が埋め尽くされている。\n", "```" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "1960年以降欠損値がない国だけを使うことにしよう。`NaN`がある列を削除する必要があるので`.dropna()`を使う。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true, "tags": [ "output_scroll" ] }, "outputs": [], "source": [ "saving = saving.dropna(axis='columns')\n", "saving.head()" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{admonition} コードの説明\n", ":class: dropdown\n", "\n", "`.dropna()`は`NaN`がある行か列を削除する。行と列のどちらを削除するかは引数`axis`で指定するが,デフォルトは`'rows'`である。即ち,引数なしで`.dropna()`を実行すると`NaN`がある行が削除される。ここでは列を削除したいので,引数に`'columns'`を指定している。\n", "```" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "AlbaniaやAngolaなどが削除されていることが確認できる。何ヵ国残っているか確認してみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "saving.shape" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{admonition} コードの説明\n", ":class: dropdown\n", "\n", "属性`.shape`は`DataFrame`の行の数(左の数字)と列(右の数字)の数を返す。\n", "```\n", "\n", "111ヵ国含まれていることが確認できた。次に,それぞれの列の平均を計算する。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "saving = saving.mean().to_frame('saving_rate') # 1\n", "saving.head()" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "````{admonition} コードの説明\n", ":class: dropdown\n", "\n", "1. `.mean()`はそれぞれの列の平均を計算し,`Series`を返す。後で`DataFrame`を結合するメソッド`.merge()`を使うために`.to_frame()`を使って`Series`を`DataFrame`に変換しており,引数`saving_rate`は列ラベルを指定している。もちろん引数を使わずに2行に分けることも可能である。\n", "```\n", "saving = saving.mean().to_frame()\n", "saving.columns = ['saving_rate']\n", "```\n", "````" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{tip}\n", "上の計算では1960年以降に欠損値が一つでもあればその国は排除されたが,全ての年でデータが揃っている経済だけを扱いたい場合に便利に使える方法である。一方で,`.groupby()`を使うと欠損値があっても平均は計算されるので,単純に`.groupby()`を使うと1960年以降に欠損値がある経済も含まれることになる。それを避けるためには一捻り必要だが,それについては[](sec:9-saving)が参考になるだろう。\n", "```" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "#### 資本減耗率" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "`saving`と同じ方法で資本減耗率の平均からなる`DataFrame`を作成する。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "depreciation = pwt.pivot(index='year', columns='country', values='delta')\n", "depreciation = depreciation.dropna(axis='columns')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "depreciation.shape" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "110ヵ国含まれている。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "depreciation = depreciation.mean().to_frame('depreciation')" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "#### 労働人口成長率" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "平均成長率を計算するには1960年と2019年の労働人口だけで計算できるが,上と同じ方法で計算してみる。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "emp = pwt.pivot(index='year', columns='country', values='emp')\n", "emp = emp.dropna(axis='columns')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "emp.shape" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "91ヵ国しか含まれていない。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "emp_growth = ( ( emp.loc[2019,:]/emp.loc[1960,:] )**(1/(len(emp)-1))-1 \n", " ).to_frame('employment_growth')\n", "emp_growth.head()" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "#### 資本ストック対GDP比" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "2019年の`cgdpo`と`cn`を使って資本ストック対GDP比を含む`DataFrame`を作成する。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ky_ratio = pwt.query('year == 2019') \\\n", " .loc[:,['country','cgdpo','cn']] \\\n", " .set_index('country') \\\n", " .dropna()\n", "ky_ratio.head()" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{admonition} コードの説明\n", ":class: dropdown\n", "\n", "`.set_index(''country')`を使って`country`を行ラベルに指定し,`.dropna()`によって欠損値がある行は削除する。\n", "```\n", "\n", "資本ストック対GDP比の列の作成しよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ky_ratio['ky_ratio'] = np.log( ky_ratio['cn'] / ky_ratio['cgdpo'] )" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "含まれる国数を確認する。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ky_ratio.shape" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "180ヵ国含まれており,`saving`や`depreciation`の国数よりも多くの国が含まれている。" ] }, { "cell_type": "markdown", "metadata": { "heading_collapsed": true, "hidden": true }, "source": [ "#### データの結合" ] }, { "cell_type": "markdown", "metadata": { "hidden": true, "tags": [ "remove-cell" ] }, "source": [ "上で作成した`DataFrame`を結合する必要があり,そのための`DataFrame`のメソッド`.merge()`の使い方を説明する。`df_left`と`df_right`の2つの`DataFrame`があるとしよう。`df_left`を左の`DataFrame`,`df_right`を右の`DataFrame`と呼ぶことにする。`df_left`のメソッド`.merge()`を使い`df_right`と結合する場合,次のコードとなる。\n", "```\n", "df_left.merge(df_right) \n", "```\n", "しかし注意が必要な点が2つある。\n", "1. 行数が同じでも`df_left`と`df_right`では行の並びが異なる可能性がある。\n", "2. 行数が異なる可能性がある。\n", "\n", "これらの問題に対応するためのる引数が用意されている。\n", "\n", "まず1つ目の問題は,ある列を基準列もしくは行ラベルに合わせて行を並び替えることにより対応できる。例えば,上で作成した`DataFrame`であれば,行ラベルが`country`になっているので,それに合わせて結合すれば良い。その場合の引数を含めたコードは次の様になる。\n", "```\n", "df_left.merge(df_right, left_index=True, right_index=True) \n", "```\n", "ここでの`left_index=True`と`right_index=True`は行ラベルを基準に結合することを指定しており,デフォルトは両方とも`False`である。行ラベルではなく,ある列を基準に結合した場合もあるだろう。その場合は次の引数を使う。\n", "```\n", "df_left.merge(df_right,\n", " left_on=<`df_left`の基準列のラベル(文字列)>,\n", " right_on=<`df_right`の基準列のラベル(文字列)>) \n", "```\n", "`left_on`は基準列に使う左の`DataFrame`にある列ラベルを文字列で指定する。同様に`right_on`は基準列に使う右の`DataFrame`にある列ラベルを文字列で指定する。デフォルトは両方とも`None`となっている。\n", "\n", "2つ目の問題は`how`という引数を使うことにより対処できる。使える値は次の4つであり,いずれも文字列で指定する。\n", "* `'inner'`:`df_left`と`df_right`の両方の基準列にある共通の行だけを残す(デフォルト)。\n", "* `'left'`:`df_left`の行は全て残し,`df_right`からはマッチする行だけが残り,対応する行がない場合は`NaN`が入る。\n", "* `'right'`:`df_right`の行は全て残し,`df_left`からはマッチする行だけが残り,対応する行がない場合は`NaN`が入る。\n", "* `'outer'`:`df_left`と`df_right`の両方の行を全て残し,マッチする行がない場合は`NaN`を入れる。\n", "\n", "では実際に上で作成した`DataFrame`を結合しよう。" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "上で作成した`DataFrame`を結合する必要があり,そのための`Pandas`の関数`.merge()`の使い方を説明する。`df_left`と`df_right`の2つの`DataFrame`があるとしよう。`df_left`を左の`DataFrame`,`df_right`を右の`DataFrame`と呼ぶことにする。2つを結合する場合,次のコードとなる。\n", "```\n", "pd.merge(df_left, df_right) \n", "```\n", "しかし注意が必要な点が2つある。\n", "1. 行数が同じでも`df_left`と`df_right`では行の並びが異なる可能性がある。\n", "2. 行数が異なる可能性がある。\n", "\n", "これらの問題に対応するためのに引数が用意されている。\n", "\n", "まず1つ目の問題は,行ラベルを基準に,もしくはある列に合わせて行を並び替えることにより対応できる。例えば,上で作成した`DataFrame`であれば,行ラベルが`country`になっているので,それに合わせて結合すれば良い。その場合の引数を含めたコードは次の様になる。\n", "```\n", "pd.merge(df_left, df_right, left_index=True, right_index=True) \n", "```\n", "ここでの`left_index=True`と`right_index=True`は行ラベルを基準に結合することを指定しており,デフォルトは両方とも`False`である。行ラベルではなく,ある列を基準に結合したい場合もあるだろう。その場合は次の引数を使う。\n", "```\n", "pd.merge(df_left, df_right,\n", " left_on=<`df_left`の基準列のラベル(文字列)>,\n", " right_on=<`df_right`の基準列のラベル(文字列)>) \n", "```\n", "`left_on`は基準列に使う`df_left`にある列ラベルを文字列で指定する。同様に`right_on`は基準列に使う`df_right`にある列ラベルを文字列で指定する。デフォルトは両方とも`None`となっている。\n", "\n", "2つ目の問題は`how`という引数を使うことにより対処できる。使える値は次の4つであり,いずれも文字列で指定する。\n", "* `'inner'`:`df_left`と`df_right`の両方の基準列にある共通の行だけを残す(デフォルト)。\n", "* `'left'`:`df_left`の行は全て残し,`df_right`からはマッチする行だけが残り,対応する行がない場合は`NaN`が入る。\n", "* `'right'`:`df_right`の行は全て残し,`df_left`からはマッチする行だけが残り,対応する行がない場合は`NaN`が入る。\n", "* `'outer'`:`df_left`と`df_right`の両方の行を全て残し,マッチする行がない場合は`NaN`を入れる。\n", "\n", "では実際に上で作成した`DataFrame`を結合しよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "for df_right in [saving, depreciation, emp_growth]: # 1\n", " \n", " ky_ratio = pd.merge(ky_ratio, df_right, # 2\n", " left_index=True, # 3\n", " right_index=True, # 4\n", " how='outer') # 5" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "```{admonition} コードの説明\n", ":class: dropdown\n", "\n", "1. `df_right`が上の説明の`df_right`に対応している。`[saving, depreciation, emp_growth]`は上で作成した`DataFrame`のリスト。\n", "2. `ky_ratio`が上の説明の`df_left`に対応している。右辺で結合した`DataFrame`を左辺にある`ky_ratio`に割り当てている(際割り当て)。\n", "3. `ky_ratio`の行ラベルを基準とすることを指定する。\n", "4. `df_right`の行ラベルを基準とすることを指定する。\n", "5. ここでの`'outer'`は左右の`DataFrame`のそれぞれの行ラベルを残し,値がない箇所には`NaN`を入れることを指定する。\n", "```\n", "\n", "結合の結果を表示してみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ky_ratio.head()" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "列AlbaniaやAngolaは`saving`,`depreciation`,`emp_growth`の`DataFram`には無いため`NaN`が入っている。" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "結合後の`ky_ratio`の情報を表示してみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "hidden": true }, "outputs": [], "source": [ "ky_ratio.info()" ] }, { "cell_type": "markdown", "metadata": { "hidden": true }, "source": [ "180ヵ国が含まれるが`NaN`がある国も多いことが分かる。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### トレンド線と散布図" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ここでは次の3つをおこなう。\n", "* 資本ストック対GDP比と次の3つの変数の散布図の表示\n", " * 貯蓄率\n", " * 資本減耗率\n", " * 労働人口増加率\n", "* 回帰分析に基づいて計算したトレンド線の表示\n", "* トレンド線の傾きの統計的優位性の表示\n", "\n", "`for`ループを使ってこれらを同時に計算・表示する。まず`ky_ratio`の列ラベルをみると,回帰分析の説明変数に使う変数が最後の3つに並んでいる。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ky_ratio.columns[-3:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "これを使い`for`ループを組んでみよう。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for var in ky_ratio.columns[-3:]: #1\n", " \n", " df_tmp = ky_ratio.copy() #2\n", " res = smf.ols(f'ky_ratio ~ {var}', #3\n", " data=df_tmp).fit() #4\n", " bhat = res.params.iloc[1] #5\n", " pval = res.pvalues.iloc[1] #6\n", " \n", " df_tmp['Trend'] = res.fittedvalues #7\n", "\n", " ax = df_tmp.plot.scatter(x=var, y='ky_ratio') #8\n", " \n", " df_tmp.sort_values('Trend').plot(x=var, #9\n", " y='Trend', \n", " color='red',\n", " ax=ax)\n", " ax.set_title(f'トレンドの傾き:{bhat:.2f}\\n' #10\n", " f'p値:{pval:.3f}', size=20) #11\n", " ax.set_ylabel('資本ストック対GDP比(対数)', #12\n", " size=15) #13\n", " ax.set_xlabel(f'{var}', size=20) #14" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{admonition} コードの説明\n", ":class: dropdown\n", "\n", "* `#1`:`ky_ratio`の最後の3列のラベルに対して`for`ループを組んで,`var`はその列ラベルを指す。\n", "* `#2`:`ky_ratio`のコピーを作り`df_tmp`に割り当てる。`.copy()`は実態としては別物のコピーを作成する。詳細は割愛するが`.copy()`がないと実態は同じで参照記号のみが異なることになり,予期しない結果につながることを防ぐために`.copy()`を使っている。\n", "* `#3`:回帰分析をおこなっているが,`f-string`を使い回帰式の説明変数を指定している。また回帰分析の結果を`res`に割り当てている。\n", "* `#4`:`data`で回帰分析のデータの指定をおこない,`.fit()`で自動計算!\n", "* `#5`:`res`の属性`.params`は推定値を2つ返すが,1番目に傾きの推定値が格納されているため`.iloc[1]`で抽出し,`bhat`に割り当てている。\n", "* `#6`:`res`の属性`.pvalues`は$p$値を2つ返すが,1番目に傾きの$p$値が格納されているため`.iloc[1]`で抽出し,`pval`に割り当てている。\n", "* `#7`:`res`の属性`fittedvalues`は予測値を返すが,それを新たな列(ラベルは`Trend`)として`df_tmp`に追加している。\n", "* `#8`:`df_tmp`を使い横軸は`var`,縦軸は`ky_ratio`の散布図を表示し、その軸を`ax`に割り当てる。\n", "* `#9`:`df_tmp`を使い横軸は`var`,縦軸は`ky_ratio`の回帰直線を表示。その際、メソッド`.sort_values('Trend')`で列`Trend`に従って昇順に並び替える。これはトレンド線が正確に表示されるために必要。\n", "* `#10`:図のタイトルを設定する。\n", " * `f-string`を使い`bhat`の値を代入する。\n", " * `:.2f`は小数点第2位までの表示を指定。\n", " * `\\n`は改行の意味。\n", " * 行を変えるので`\\n`の後に`'`が必要となる。\n", "* `#11`:`f-string`を使い`pval`の値を代入する。`:.3f`は小数点第3位までの表示を指定し,`size=20`はフォントの大きさの指定。\n", "* `#12`:縦軸のラベルの設定。\n", "* `#13`:フォントの大きさの指定。\n", "* `#14`:横軸のラベルの設定であり,`f-string`を使い`var`の値を代入している。`size=20`はフォントの大きさの指定。\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "3つの図からソロー・モデルの理論的予測はデータと整合性があることが確認できる。ここで注意する点が一つある。式[](eq:8-kyratio)は因果関係を予測している。例えば,貯蓄率が高くなることにより長期的な一人\n", "当たりGDPは増加する。一方,トレンド線は因果関係を示しているのではなく単なる相関関係を表している。ソロー・モデルの因果関係を計量経済学的に検討するにはさまざまな要因の検討が必要になり,本章の域を超える事になる。" ] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 4 }