Mímisbrunnr知恵の泉

← 意思決定分析 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:支配と許容性 | 関連:多属性効用理論(MAUT)CVaR(期待ショートフォール)(リスク・リターンのフロンティア)

要点(BLUF)

1. 多目的問題とトレードオフ

意思決定の基準が1つなら、最大化するだけで終わりです。難しさは基準が複数あり、しかも衝突するときに生まれます。車を選ぶなら「安い・速い・快適」を全部欲しいが、安い車は遅く、速い車は高い。ある目的を立てれば別の目的が立たない——これがトレードオフです。

このとき「最良の1つ」は一般に存在しません。代わりに問うべきは「少なくとも検討に値する案はどれか」。その答えがパレート最適です。

2. パレート最適の定義

すべての目的を「大きいほど良い」に揃えたとき(コストのような小さいほど良い目的は符号を反転)、解 xx が解 yyパレート支配されるとは、

fk(y)fk(x) (すべての目的 k)かつfk(y)>fk(x) (ある k)f_k(y) \ge f_k(x)\ (\text{すべての目的 } k) \quad\text{かつ}\quad f_{k^\ast}(y) > f_{k^\ast}(x)\ (\text{ある } k^\ast)

が成り立つことです。どの目的でも yyxx 以上で、少なくとも1つで真に勝る。このとき xx を選ぶ理由はありません。誰にも支配されない解がパレート最適です。

支配と許容性の支配とまったく同じ構造で、「状態」が「目的」に置き換わっただけ。だからコードもほぼ流用できます。

import numpy as np

alt = ["A", "B", "C", "D"]
performance = np.array([90, 70, 80, 60])     # 性能(高いほど良い)
cost        = np.array([300, 150, 250, 200]) # コスト(低いほど良い)
# 両方「大きいほど良い」に変換(コストは符号反転)
obj = np.column_stack([performance, -cost])

def pareto_optimal(M):
    n = M.shape[0]; optimal = []
    for i in range(n):
        dominated = any(np.all(M[j] >= M[i]) and np.any(M[j] > M[i])
                        for j in range(n) if j != i)
        if not dominated:
            optimal.append(i)
    return optimal

po = pareto_optimal(obj)
for i, a in enumerate(alt):
    print(f"{a}: 性能={performance[i]}, コスト={cost[i]}")
print("パレート最適(非支配)->", [alt[i] for i in po])

出力:

A: 性能=90, コスト=300
B: 性能=70, コスト=150
C: 性能=80, コスト=250
D: 性能=60, コスト=200
パレート最適(非支配)-> ['A', 'B', 'C']

出力の意味:Dは脱落します。Dは性能60・コスト200ですが、Bは性能70・コスト150——性能でもコストでもBがDより良いので、DはBに支配されます。残るA・B・Cは互いに支配されません:Aは最高性能だが高い、Bは最安だが性能控えめ、Cはその中間。性能とコストのどちらを重視するかで勝者が変わるので、3つとも「検討に値する」のです。

3. パレートフロンティアの可視化

非支配解を2目的平面に置くと、右上がりの境界線(フロンティア)を描きます。

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

alt = ["A", "B", "C", "D"]
performance = np.array([90, 70, 80, 60])
cost = np.array([300, 150, 250, 200])
obj = np.column_stack([performance, -cost])

def pareto_optimal(M):
    n = M.shape[0]; opt = []
    for i in range(n):
        dom = any(np.all(M[j] >= M[i]) and np.any(M[j] > M[i])
                  for j in range(n) if j != i)
        if not dom: opt.append(i)
    return opt

po = pareto_optimal(obj)
plt.figure(figsize=(6.5, 4.5))
for i, a in enumerate(alt):
    is_po = i in po
    plt.scatter(cost[i], performance[i], s=120,
                color="crimson" if is_po else "gray",
                marker="o" if is_po else "x", zorder=5)
    plt.annotate(a, (cost[i], performance[i]),
                 textcoords="offset points", xytext=(8, 5))
po_sorted = sorted(po, key=lambda i: cost[i])
plt.plot(cost[po_sorted], performance[po_sorted], "--", color="crimson",
         alpha=0.6, label="パレートフロンティア")
plt.xlabel("コスト(低いほど良い →)"); plt.ylabel("性能(高いほど良い ↑)")
plt.title("2目的のパレート最適(赤=非支配、灰=支配される)")
plt.legend(); plt.grid(alpha=0.3); plt.tight_layout(); plt.show()

図の意味:赤い丸(A・B・C)が非支配解で、破線がフロンティア。灰色のD(×)はフロンティアの内側(左下)にあり、フロンティア上の点より性能もコストも劣ります。フロンティアの内側は改善余地あり、フロンティア上は「ここから先はトレードオフ」 という境界。意思決定は「内側の案を捨ててフロンティアに乗る」→「フロンティア上のどこに乗るかを価値判断で決める」の2段階になります。

4. フロンティアの先:価値判断が要る

パレート最適は複数残るのが普通で、ここから1つを選ぶには目的の相対的な重要度(重み) という価値判断が必要です。これは数学では決められません——「性能とコスト、どちらをどれだけ重視するか」は意思決定者の選好です。

その重みを明示的に置いて基準を1つに束ねるのが多属性効用理論(MAUT)、重みを一対比較から系統的に引き出すのが階層分析法(AHP)です。なお、リスクとリターンのトレードオフを描くCVaR(期待ショートフォール)の効率的フロンティアも、まったく同じ「非支配集合」の発想——多目的最適化はリスク管理にも顔を出します。

数式の直観的意味:なぜ重み付き和で端点が出るか

各目的に重み wk0w_k \ge 0 を付けて加重和 kwkfk(x)\sum_k w_k f_k(x) を最大化すると、得られる解は必ずパレート最適です(重みが正なら、支配される解は加重和でも負ける)。逆に、目的空間が凸ならフロンティア上の各点は、ある重みの加重和の最大解として表せます。重みを動かすことは、フロンティア上を滑ることに対応します。重みを変えて最適解がどう動くかを追えば、フロンティア全体をなぞれる——これが重み付けと感度分析の感度分析の幾何学的な意味です。ただし非凸なフロンティアでは、加重和では到達できない「くぼみ」の点があり、そこは別の方法(ε制約法など)が要ります。

⚠️ よくある誤解

対応シミュレーション

本文のコードは任意の多目的データに使えます。案を増やして散布させると、フロンティアと内側の支配される点が見分けられ、トレードオフの形(凸か非凸か)も観察できます。

関連ノート