縁故主義経済シミュレーション その2¶

(Version 0.0.2)

Gemini 2.5 Flash (with Canvas) さんと共に、決められた成長率の中で、経済をよくしようとすると少子化が避けられなかったことをシミュレーションでだいたい示した。

前回↓のようなシミュレーションをした。

《nepotism_economy.ipynb - 縁故主義経済シミュレーション - GitHub Gist》
https://gist.github.com/JRF-2018/409d9c3e7b1b36388ae9b5f8b76fb21b

縁故主義(ネポティズムとかクローニー・キャピタリズムとか)よりそうでない非縁故主義のほうが投資ボリュームが増えるというのを経済モデルまたはシミュレーションで示せないかと考えた。

縁故主義だと、商店のリスクがまるわかりのため小さいリスクで投資を引き上げる。縁故主義でないと、わりとリスクがあっても投資が続く。これが広がると、縁故主義でないほう が経済も大きくなって機会も増え、投資ボリュームが増えてもやっていける。…みたいなことが起きると考えた。

(…)

結論としては、投資環境が良いときは非縁故主義が勝つことが示せた。逆に言えば投資環境が普通以下の場合は、縁故主義が勝ってしまって、もともと私が示したかったようにはいかなかった。

前回のシミュレーションは不服だった。非縁故主義経済はもっと縁故主義経済より有利なはずだ。縁故主義に不正があるとかそういうこととは関係がなく。 そのためには、経済において、リスク許容度を上げれば、乗数効果みたいなもので、経済自体が大きくなることを示したかった。これは意図した投資に対し、実際実現する投資の額が大きいということである。

縁故主義経済では意図した投資が少なくなるということだろうか? しかし、超安全資産(現金)みたいなものを考えて、そこに縁故主義経済が投資を集中させるとしても、あまり意味ある結果は出せなかった。

逆に考えよう。意図した投資総量は縁故主義も非縁故主義も変わらないとどうもせざるを得ない。それで次期に向けて実現した投資が逆に一定とする。するとリスク許容度によって、だいたい経済の良さ(前回の PROFIT_RISK_MAG)が変化するだろう。例えば縁故主義的にリスク許容度を下げると、経済を良くしなければ目的とする次期投資総額が実現しない…などと言えるなら、「リスク許容度を上げれば、乗数効果みたいなもので、経済自体が大きくなる」(の逆)が言えたことになるのではないか。

ここから敷衍して、前回の実験1のプログラムについて考えた。

まず実験1の補足から。商店のリスクがわからないという部分を確率的に表現しても、結局のところ、単純に縁故主義だとリスク許容度が小さく、非縁故主義だとリスク許容度が大きいというプログラムにするしかなく、リスクがわからないという確率部分は結果をぼやけさせる効果しかない(はず)。そこで前回の実験1のように割り切って、経済がどのように大きくなるかを見たことになる。

この実験1のとき期首投資総額 I0 (= total_capital) と 期末投資総額 I1 = r I0 (次期の total_capital) が決まっているとき許容リスク q (= SAFE_THRESHOLD) について、m (= PROFIT_RISK_MAG) が決まるとき、m を q r I0 の数式で表す、または、プログラムで図示できないか…。そう Gemini さんに尋ねたところ、数式で表すのは難しいが図示することはできると回答を得た。

その上で、こう表したとき、少子化を実現するため r を小さく制限したのではないか(制限を国際的に強制されたのではないか)という疑いを私は抱いた。このとき q が小さくなり、子を生めるような環境の企業体が減ったことを示せると考えた。ある種の陰謀論である。

結果を見ると、だいたいそのようなことは示せたが、Gemini さんは「陰謀論」をやんわり否定し、r が決まっているというよりも大きな r (成長率)を目指す中であくまでそういうこともあるかもしれない…ぐらいのトーンしか受け容れてもらえなかった。

Gemini さんとの会話は↓である。ただ、現状では Canvas 部分については完全には共有されないようだ。

https://g.co/gemini/share/e3f466943e5a

実験¶

では、実験に入る。パラメータ以外はほぼ Gemini 2.5 Flash (with Canvas) さんの書いたものである。ただし、実験1に相当する部分が含まれているので、まったく私の創作部分がないということもない。

このプログラムでは等高線を使って図示がなされる。私は r を固定して q と m の変化を見たかったのだが、そのためには PyStan のようなもので m を求める必要があるのかとか悩んでいた。しかし Gemini さんはシミュレーション結果から単に等高線を描くプログラムを描いていてきた。これまで自分の実験で「等高線」を使ったことがほぼなかった私は、それに何の意味があるのか…と思っていたのだが、出てきたグラフを解釈するうちに、それは私が欲しかった r を固定して q と m の変化を見るものそのものであることを理解できた。この Gemini さんの提案はありがたかった。

In [ ]:
import random
import numpy as np
from scipy.stats import sem
import matplotlib.pyplot as plt

# 乱数シード
np.random.seed(42)

# --- シミュレーションパラメータ ---
RUNS = 20   # シミュレーション実行回数 (平均化のため複数回実行 - 等高線描画のため少し増やしました)

NUM_INVESTORS = 100  # 投資家数
NUM_BUSINESSES = 200 # 事業数
INITIAL_TOTAL_CAPITAL = 100000 # 経済全体の初期総資金
NUM_PERIODS = 30     # シミュレーション期間(期)

# 事業のリスクとリターンに関するパラメータ
# リスクレベル(0:低リスク ~ 1:高リスク)
def business_risk_levels ():
    return [random.random() for _ in range(NUM_BUSINESSES)]

# 成功確率 = 1 - リスクレベル
def success_probability (risk_levels):
    return [1 - risk for risk in risk_levels]

# 成功時のリターン倍率 (投資額に対する回収+利益)
# リスクが高いほど成功時のリターンも大きいと仮定
def return_multiplier (risk_levels):
    return [1.0 + risk * 1.5 for risk in risk_levels]

# 投資家の判断に関するパラメータ
# 安全投資閾値(このリスク以下の事業に優先投資)
# この値を変化させてシミュレーションを行います (q に相当)
# SAFE_THRESHOLD = 0.5 # この値はシミュレーション時に上書きされます

# リスク回避度(閾値以上のリスクへの投資を控える度合い)
RISK_AVERSION = 0.8

# 事業収益環境
# この値を変化させてシミュレーションを行います (m に相当)
# PROFIT_RISK_MAG = 0.5 # この値はシミュレーション時に上書きされます


# --- シミュレーション関数 ---

def run_single_simulation(initial_capital, num_periods, safe_threshold, profit_risk_mag):
    """
    単一のシミュレーションを実行し、最終総資金を返す関数

    Args:
        initial_capital (float): 初期総資金
        num_periods (int): シミュレーション期間
        safe_threshold (float): 安全投資閾値 (q)
        profit_risk_mag (float): 事業収益環境パラメータ (m)

    Returns:
        float: 最終期の経済全体の総資金
    """
    total_capital = initial_capital

    # 事業のリスク、成功確率、リターン倍率をランダムに生成(各シミュレーションで異なる環境)
    # 等高線描画のため、各シミュレーション実行ごとに異なる事業環境を生成
    business_risk_levels_run = business_risk_levels()
    success_probability_run = success_probability(business_risk_levels_run)
    return_multiplier_run = return_multiplier(business_risk_levels_run)

    for period in range(num_periods):
        investor_capital = total_capital / NUM_INVESTORS
        if investor_capital <= 0:
            return total_capital # 資金が尽きたら終了

        period_total_investment = 0
        business_investments = [0] * NUM_BUSINESSES

        # 投資ラウンド
        for investor_id in range(NUM_INVESTORS):
            available_to_invest = investor_capital
            potential_businesses = list(range(NUM_BUSINESSES))
            random.shuffle(potential_businesses)

            for business_id in potential_businesses:
                risk = business_risk_levels_run[business_id]
                investment_amount = 0
                if risk <= safe_threshold:
                    investment_amount = available_to_invest * (1 - risk)
                else:
                    investment_amount = available_to_invest * (1 - risk) * (1 - RISK_AVERSION)

                if investment_amount > 0:
                    actual_investment = min(investment_amount, available_to_invest)
                    business_investments[business_id] += actual_investment
                    period_total_investment += actual_investment
                    available_to_invest -= actual_investment
                    if available_to_invest <= 0:
                        break

        # 事業の成果判定と資金更新
        period_return = 0
        for business_id in range(NUM_BUSINESSES):
            if business_investments[business_id] > 0:
                # 成功確率に profit_risk_mag を適用
                if random.random() < success_probability_run[business_id] ** profit_risk_mag:
                    period_return += business_investments[business_id] * return_multiplier_run[business_id]

        total_capital = total_capital - period_total_investment + period_return

    return total_capital

def plot_growth_rate_contour():
    """
    SAFE_THRESHOLD (q) と PROFIT_RISK_MAG (m) の平面上で
    経済成長率の等高線プロットを作成する関数
    """
    # 変化させるパラメータの範囲と分割数
    q_values = np.linspace(0.1, 0.9, 20) # q の値の範囲とグリッド数
    m_values = np.linspace(0.5, 1.0, 20) # m の値の範囲とグリッド数

    # 結果を保存する2次元配列 (mの数 x qの数)
    growth_rates = np.zeros((len(m_values), len(q_values)))

    print("--- 等高線プロット用シミュレーション開始 ---")

    # グリッド上の各点(q, m)でシミュレーションを実行
    for i, m in enumerate(m_values):
        print(f"PROFIT_RISK_MAG (m): {m:.2f} をシミュレーション中...")
        for j, q in enumerate(q_values):
            final_capitals = []
            for run in range(RUNS):
                final_capital = run_single_simulation(INITIAL_TOTAL_CAPITAL, NUM_PERIODS, q, m)
                final_capitals.append(final_capital)
            # 平均成長率を計算 (最終資金 / 初期資金)
            growth_rates[i, j] = np.mean(final_capitals) / INITIAL_TOTAL_CAPITAL

    print("--- 等高線プロット用シミュレーション終了 ---")

    # 等高線プロットの作成
    plt.figure(figsize=(10, 7))

    # グリッドデータを作成
    Q, M = np.meshgrid(q_values, m_values)

    # 等高線(塗りつぶし)
    contourf = plt.contourf(Q, M, growth_rates, levels=np.linspace(growth_rates.min(), growth_rates.max(), 20), cmap='RdYlGn')
    plt.colorbar(contourf, label=f'Growth Rate (Final Capital / Initial Capital) after {NUM_PERIODS} periods')

    # 等高線(線)とラベル
    contour = plt.contour(Q, M, growth_rates, levels=np.linspace(growth_rates.min(), growth_rates.max(), 10), colors='black', linestyles='dashed')
    plt.clabel(contour, inline=True, fontsize=8, fmt='%1.2f')


    plt.xlabel('SAFE_THRESHOLD (q)')
    plt.ylabel('PROFIT_RISK_MAG (m)')
    plt.title('Contour Plot of Economic Growth Rate on q-m Plane')
    plt.grid(True, linestyle='dotted')
    plt.show()

# 等高線プロット用シミュレーションを実行
plot_growth_rate_contour()
--- 等高線プロット用シミュレーション開始 ---
PROFIT_RISK_MAG (m): 0.50 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.53 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.55 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.58 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.61 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.63 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.66 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.68 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.71 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.74 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.76 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.79 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.82 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.84 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.87 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.89 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.92 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.95 をシミュレーション中...
PROFIT_RISK_MAG (m): 0.97 をシミュレーション中...
PROFIT_RISK_MAG (m): 1.00 をシミュレーション中...
--- 等高線プロット用シミュレーション終了 ---
No description has been provided for this image

結論¶

上のグラフは一定の成長率について山になっている部分があるのがポイントである。例えば、r = 10.18 の山を見るとき、山の左側を見ると、より少ない q のほうが、より景気の良い状態(m の小さい状態)を実現できる。これを目指したのが例えば、失なわれたウン十年の日本であり、少ない q を目指す安定指向が少子化を加速したと考えられる。逆に山の右側を見ると、より q が大きく、より景気の良い状態を目指せたと見ることができる。こちらは途上国モデルに相当するのかもしれない。

このようなことを Gemini さんにぶつけると、だいたい次のような見解を得た。

ご指摘のように、この山の左側(q が小さい側)と右側(q が大きい側)で同じ成長率を達成できる組み合わせが存在するという点は、異なる経済モデルや戦略を示唆している可能性があります。

  • 山の左側(q が小さい): これは、投資家があまりリスクを取らない状況でも、ある程度の成長率を達成できる組み合わせがあることを示しています。もし日本のような成熟した経済が、安定志向の投資(小さい q)を重視しつつ、特定の事業環境(特定の m の値)を整えることで、この山の左側の等高線上の成長率を目指したと考えることもできます。この場合、「より少ない q のほうがより景気の良い状態を実現できた」というよりは、「少ない q でもこの程度の成長率を維持できた」と解釈する方が近いかもしれません。ただし、この領域は m の値が比較的大きい(事業が成功しにくい)場合でも成り立ちうるため、安定はしているものの、爆発的な成長は期待しにくい状況とも言えます。

  • 山の右側(q が大きい): こちらは、投資家がよりリスクを取ることで、同じ成長率を達成できる組み合わせがあることを示しています。途上国が急速な経済成長を目指す際に、リスクの高い新規事業への投資(大きい q)を積極的に行い、同時に事業環境(m)を改善していくことで、この山の右側の等高線上の成長率を目指す、というモデルが考えられます。この場合、「より q が大きく、より景気の良い状態を実現できた」という解釈が当てはまる可能性があります。リスクは伴いますが、成功すれば大きなリターンが得られる機会が多い状況と言えます。

同じ成長率の等高線上であっても、q と m の異なる組み合わせが存在することは、経済がどのような「質」の成長を目指すか、あるいはどのような制約の中で成長を目指すかによって、最適な戦略や結果としてたどり着く状態が異なりうることを示唆しています。

「子供を生める環境」という比喩で言えば、q が小さい左側は、リスクは少ないが大きな機会も少ない「安定した環境」であり、少子化が進むような状況と関連付けられるかもしれません。一方、q が大きい右側は、リスクは高いが成功すれば大きなリターンが得られる「機会に満ちた環境」であり、人口が増加したり活気がある状況と関連付けられるかもしれません。

もちろん、これはシミュレーションモデルに基づいた解釈であり、現実の経済はさらに多くの要因が複雑に絡み合っています。しかし、この等高線プロットは、q と m という二つのパラメータが経済成長に与える影響とその相互作用を考える上で、非常に示唆に富む結果と言えるでしょう。