Lab Research ポートフォリオ理論の基礎——分散投資でリスクを減らす数学的仕組み
目次
「卵を一つのカゴに盛るな」——これは投資の世界で広く信じられている教訓だ。しかし、なぜ分散投資はリスクを減らすのか。数学的に理解している投資家は少ない。本稿では現代ポートフォリオ理論(MPT)の基礎を、Python 実装とともに解説する。
1. 個別資産のリターンとリスク
1.1 期待リターンの計算
期待リターンは過去のリターンの平均、または将来シナリオの確率加重平均で推定する。
import numpy as np
# 株式 A の過去 5 年の年間リターン(%)
returns_A = np.array([8.5, -2.3, 12.1, 5.7, -4.0])
# 期待リターン(平均リターン)
expected_return_A = np.mean(returns_A)
print(f"株式 A の期待リターン:{expected_return_A:.2f}%") # 4.00%
1.2 リスクの計算——標準偏差
リスクはリターンのばらつき(標準偏差)で測定する。
# リスク(標準偏差)
risk_A = np.std(returns_A, ddof=1) # 不偏標準偏差
print(f"株式 A のリスク(標準偏差):{risk_A:.2f}%") # 6.22%
標準偏差の意味:
- 標準偏差 6.22% は、約 68% の確率でリターンが「平均±6.22%」の範囲に入ることを意味する
- 95% の確率なら「平均±2×標準偏差」の範囲(信頼区間)
2. 2 資産ポートフォリオ——分散投資の効果
2.1 ポートフォリオの期待リターン
ポートフォリオの期待リターンは個別資産の期待リターンの加重平均だ。
E[Rp] = w₁ × E[R₁] + w₂ × E[R₂]
ここで:
w₁, w₂ = 各資産の組成比率(w₁ + w₂ = 1)
E[R₁], E[R₂] = 各資産の期待リターン
# 株式 A と株式 B
returns_B = np.array([6.2, 3.1, -1.5, 8.9, 4.3])
expected_return_B = np.mean(returns_B)
print(f"株式 B の期待リターン:{expected_return_B:.2f}%") # 4.20%
# ポートフォリオ(50%ずつ)
w_A, w_B = 0.5, 0.5
portfolio_expected_return = w_A * expected_return_A + w_B * expected_return_B
print(f"ポートフォリオの期待リターン:{portfolio_expected_return:.2f}%") # 4.10%
2.2 ポートフォリオのリスク——共分散が鍵
ポートフォリオのリスクは、個別リスクの単純平均ではない。
σp² = w₁²σ₁² + w₂²σ₂² + 2w₁w₂Cov(R₁,R₂)
ここで:
σp² = ポートフォリオの分散
σ₁², σ₂² = 個別資産の分散
Cov(R₁,R₂) = 共分散(2 資産のリターンの連動度)
共分散:2 つの資産が一緒に動く傾向
- 正の共分散:同じ方向に動く
- 負の共分散:逆の方向に動く
- 0:無関係
# 共分散の計算
cov_AB = np.cov(returns_A, returns_B, ddof=1)[0, 1]
print(f"株式 A と B の共分散:{cov_AB:.4f}")
# 相関係数(-1 〜 +1 の標準化された指標)
corr_AB = np.corrcoef(returns_A, returns_B)[0, 1]
print(f"株式 A と B の相関係数:{corr_AB:.4f}")
# ポートフォリオの分散
var_A = np.var(returns_A, ddof=1)
var_B = np.var(returns_B, ddof=1)
portfolio_var = w_A**2 * var_A + w_B**2 * var_B + 2 * w_A * w_B * cov_AB
portfolio_risk = np.sqrt(portfolio_var)
print(f"ポートフォリオのリスク(標準偏差):{portfolio_risk:.2f}%")
2.3 分散投資の効果
# 個別資産のリスクの単純平均
simple_avg_risk = (risk_A + np.std(returns_B, ddof=1)) / 2
print(f"個別リスクの平均:{simple_avg_risk:.2f}%")
print(f"ポートフォリオリスク:{portfolio_risk:.2f}%")
print(f"リスク低減効果:{simple_avg_risk - portfolio_risk:.2f}%")
なぜリスクが減少するか:
- 2 資産が完全に連動しない限り(相関<1)、一部のリスクが相殺される
- 一方が下落しても、他方が下落しない場合、損失が緩和される
2.4 相関係数と分散効果
| 相関係数 | 関係 | 分散効果 |
|---|---|---|
| +1.0 | 完全な正の相関 | なし(リスク低減なし) |
| +0.5 | 正の相関 | ややあり |
| 0 | 無相関 | あり |
| -0.5 | 負の相関 | 大きい |
| -1.0 | 完全な負の相関 | 最大(理論上リスク 0 も可能) |
# 相関係数を変えたポートフォリオリスクの計算
def portfolio_risk_with_correlation(risk1, risk2, w1, correlation):
"""相関係数からポートフォリオリスクを計算"""
cov = correlation * risk1 * risk2 # 共分散 = 相関 × σ1 × σ2
var1, var2 = risk1**2, risk2**2
w2 = 1 - w1
port_var = w1**2 * var1 + w2**2 * var2 + 2 * w1 * w2 * cov
return np.sqrt(port_var)
# 株式 A と B のリスク
risk_A = np.std(returns_A, ddof=1)
risk_B = np.std(returns_B, ddof=1)
for corr in [1.0, 0.5, 0.0, -0.5, -1.0]:
pr = portfolio_risk_with_correlation(risk_A, risk_B, 0.5, corr)
print(f"相関係数 {corr:+.1f}: ポートフォリオリスク = {pr:.2f}%")
出力例:
相関係数 +1.0: ポートフォリオリスク = 6.10%
相関係数 +0.5: ポートフォリオリスク = 5.30%
相関係数 +0.0: ポートフォリオリスク = 4.37%
相関係数 -0.5: ポートフォリオリスク = 3.23%
相関係数 -1.0: ポートフォリオリスク = 1.54%
3. 多資産ポートフォリオ——n 資産への拡張
3.1 期待リターンと分散の行列表現
E[Rp] = w^T × μ
σp² = w^T × Σ × w
ここで:
w = 重みベクトル
μ = 期待リターンベクトル
Σ = 分散共分散行列
# 5 資産のポートフォリオ
np.random.seed(42)
n_assets = 5
n_years = 20
# 模擬リターンデータ(正規分布から生成)
returns = np.random.normal(loc=0.05, scale=0.15, size=(n_years, n_assets))
# 各資産の期待リターンとリスク
expected_returns = np.mean(returns, axis=0)
risks = np.std(returns, axis=0, ddof=1)
# 分散共分散行列
cov_matrix = np.cov(returns.T, ddof=1)
print("期待リターン:", expected_returns)
print("リスク(標準偏差):", risks)
print("分散共分散行列:\n", cov_matrix)
3.2 等ウェイトポートフォリオ
# 等ウェイト(1/n で分散)
weights_equal = np.array([1/n_assets] * n_assets)
# ポートフォリオの期待リターン
port_return_equal = np.dot(weights_equal, expected_returns)
# ポートフォリオのリスク
port_var_equal = np.dot(weights_equal.T, np.dot(cov_matrix, weights_equal))
port_risk_equal = np.sqrt(port_var_equal)
print(f"等ウェイトポートフォリオ")
print(f"期待リターン:{port_return_equal*100:.2f}%")
print(f"リスク:{port_risk_equal*100:.2f}%")
4. 効率的フロンティア——最適ポートフォリオの集合
4.1 効率的フロンティアとは
効率的フロンティアは**「同じリスクで最大の期待リターン」または「同じリターンで最小リスク」**のポートフォリオの集合だ。
import matplotlib.pyplot as plt
def generate_efficient_frontier(expected_returns, cov_matrix, n_points=100):
"""効率的フロンティアを生成(簡易版)"""
n_assets = len(expected_returns)
# ランダムなポートフォリオを 10000 個生成
n_portfolios = 10000
results = np.zeros((3, n_portfolios))
weights_record = []
for i in range(n_portfolios):
# ランダムな重み
weights = np.random.random(n_assets)
weights /= np.sum(weights) # 合計を 1 に正規化
weights_record.append(weights)
# ポートフォリオのリターン・リスク・シャープレシオ
port_return = np.dot(weights, expected_returns)
port_var = np.dot(weights.T, np.dot(cov_matrix, weights))
port_std = np.sqrt(port_var)
results[0, i] = port_std # リスク
results[1, i] = port_return # リターン
results[2, i] = port_return / port_std # シャープレシオ(リスクフリーレート 0 と仮定)
return results, weights_record
# 効率的フロンティアの生成
results, weights = generate_efficient_frontier(expected_returns, cov_matrix)
# プロット
plt.figure(figsize=(10, 6))
plt.scatter(results[0, :], results[1, :], c=results[2, :], marker='o', cmap='viridis', alpha=0.5)
plt.colorbar(label='シャープレシオ')
plt.xlabel('リスク(標準偏差)')
plt.ylabel('期待リターン')
plt.title('効率的フロンティア')
plt.grid(True, alpha=0.3)
plt.show()
4.2 最小分散ポートフォリオ
最小分散ポートフォリオはリスクが最小のポートフォリオだ。
from scipy.optimize import minimize
def portfolio_variance(weights, cov_matrix):
"""ポートフォリオ分散の計算"""
return np.dot(weights.T, np.dot(cov_matrix, weights))
def find_minimum_variance_portfolio(cov_matrix, n_assets):
"""最小分散ポートフォリオの重みを求める"""
# 初期値(等ウェイト)
init_guess = np.array([1/n_assets] * n_assets)
# 制約:重みの合計 = 1
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
# 境界:各重みは 0 以上 1 以下
bounds = tuple((0, 1) for _ in range(n_assets))
# 最適化
result = minimize(
portfolio_variance,
init_guess,
args=(cov_matrix,),
method='SLSQP',
bounds=bounds,
constraints=constraints
)
return result.x
# 最小分散ポートフォリオ
min_var_weights = find_minimum_variance_portfolio(cov_matrix, n_assets)
min_var_return = np.dot(min_var_weights, expected_returns)
min_var_risk = np.sqrt(portfolio_variance(min_var_weights, cov_matrix))
print(f"最小分散ポートフォリオ")
print(f"重み:{min_var_weights}")
print(f"期待リターン:{min_var_return*100:.2f}%")
print(f"リスク:{min_var_risk*100:.2f}%")
4.3 最大シャープレシオポートフォリオ
シャープレシオはリスク 1 単位あたりの超過リターンを表す。
シャープレシオ = (E[Rp] - Rf) / σp
ここで:
Rf = リスクフリーレート(国債利回り等)
def negative_sharpe_ratio(weights, expected_returns, cov_matrix, risk_free_rate):
"""負のシャープレシオ(最小化問題にするため)"""
port_return = np.dot(weights, expected_returns)
port_var = np.dot(weights.T, np.dot(cov_matrix, weights))
port_std = np.sqrt(port_var)
return -(port_return - risk_free_rate) / port_std
def find_max_sharpe_portfolio(expected_returns, cov_matrix, risk_free_rate=0.01):
"""最大シャープレシオポートフォリオ"""
n_assets = len(expected_returns)
init_guess = np.array([1/n_assets] * n_assets)
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
bounds = tuple((0, 1) for _ in range(n_assets))
result = minimize(
negative_sharpe_ratio,
init_guess,
args=(expected_returns, cov_matrix, risk_free_rate),
method='SLSQP',
bounds=bounds,
constraints=constraints
)
return result.x
# 最大シャープレシオポートフォリオ
max_sharpe_weights = find_max_sharpe_portfolio(expected_returns, cov_matrix)
max_sharpe_return = np.dot(max_sharpe_weights, expected_returns)
max_sharpe_risk = np.sqrt(portfolio_variance(max_sharpe_weights, cov_matrix))
max_sharpe = (max_sharpe_return - 0.01) / max_sharpe_risk
print(f"最大シャープレシオポートフォリオ")
print(f"重み:{max_sharpe_weights}")
print(f"期待リターン:{max_sharpe_return*100:.2f}%")
print(f"リスク:{max_sharpe_risk*100:.2f}%")
print(f"シャープレシオ:{max_sharpe:.3f}")
5. 実践的な分散投資
5.1 資産クラス間の相関
| 資産ペア | 典型的な相関係数 |
|---|---|
| 先進国株式 ↔ 先進国債券 | -0.2 〜 +0.2 |
| 先進国株式 ↔ 新興国株式 | +0.5 〜 +0.8 |
| 株式 ↔ 商品(金) | -0.1 〜 +0.3 |
| 株式 ↔ REIT | +0.5 〜 +0.7 |
| 先進国債券 ↔ 新興国債券 | +0.3 〜 +0.6 |
分散投資のポイント:
- 相関係数が低い資産を組み合わせるほど、分散効果は大きい
- 株式と債券の組み合わせが古典的だが有効
5.2 ナシオの分散——銘柄数とリスク低減
def diversification_effect(n_stocks, idiosyncratic_risk=0.25):
"""銘柄数による非系統リスクの低減"""
# 非系統リスク = 個別リスク / √n
remaining_risk = idiosyncratic_risk / np.sqrt(n_stocks)
return remaining_risk
# 銘柄数によるリスク低減
for n in [1, 5, 10, 20, 50, 100]:
risk = diversification_effect(n)
reduction = (1 - risk / 0.25) * 100
print(f"{n}銘柄:残余リスク {risk*100:.1f}%({reduction:.0f}%低減)")
出力:
1 銘柄:残余リスク 25.0%(0% 低減)
5 銘柄:残余リスク 11.2%(55% 低減)
10 銘柄:残余リスク 7.9%(68% 低減)
20 銘柄:残余リスク 5.6%(78% 低減)
50 銘柄:残余リスク 3.5%(86% 低減)
100 銘柄:残余リスク 2.5%(90% 低減)
重要な知見:
- 30 銘柄程度で非系統リスクの約 90% が消える
- これ以上増やしても分散効果は限定的(限界効用逓減)
5.3 グローバル分散
# 地域別株式インデックスの相関(例)
correlation_matrix = np.array([
[1.00, 0.72, 0.68, 0.55], # 日本
[0.72, 1.00, 0.80, 0.70], # 米国
[0.68, 0.80, 1.00, 0.75], # 欧州
[0.55, 0.70, 0.75, 1.00], # 新興国
])
# 日本株は他地域と比較的低い相関(特に新興国)
# 米国・欧州は高い相関だが、完全な 1 ではない
グローバル分散の効果:
- 一国の経済リスクに依存しない
- 為替リスクも分散(円高時に外貨資産が評価増)
6. ポートフォリオ理論の限界
6.1 前提仮定の現実性
| 仮定 | 現実 |
|---|---|
| リターンは正規分布 | ファットテール(極端な事象)が実際には発生 |
| 相関は一定 | 危機時に相関が 1 に収束(2008 年金融危機) |
| 投資家は合理的 | 行動経済学:実際は感情的・バイアスあり |
| 取引コスト・税金なし | 実際には売買手数料・税金がかかる |
6.2 ブラック・スワン事象
2008 年金融危機や 2020 年コロナショックのような稀で極端な事象は、正規分布ベースのモデルでは予測できない。
対策:
- リスクパリティ(リスク貢献度を均等化)
- タールリスクヘッジ(プットオプションなど)
- 流動性リスクの考慮
まとめ
ポートフォリオ理論の核心は以下の通り:
- 分散投資は数学的にリスク低減効果がある(相関<1 なら必ず効果)
- 効率的フロンティアは最適ポートフォリオの軌跡
- 最小分散ポートフォリオはリスク最小、最大シャープレシオはコストパフォーマンス最適
- 30 銘柄程度で非系統リスクの 90% が消える
- 理論には限界(ファットテール、相関変動)もあるため、盲信は禁物
分散投資は「免费のランチ(free lunch)」と呼ばれる。リターンを犠牲にせずリスクだけを低減できる、ほぼ唯一の方法だ。
免責事項 — 当記事は情報提供を目的としており、特定の金融商品の売買を推奨するものではありません。投資判断はご自身の責任で行ってください。