このページで扱う主要キーワード(クリックで該当セクションへ):
「連続最適化」 (Continuous Optimization) は、 SSDSE-B-2026 などの公的統計データを使った教材・分析で頻出するキーワードです。 本ページでは、 まず直感、 次に数式、 そして 47 都道府県の実値で確かめる、 という流れで体系的に整理します。 加えて、 ケーススタディ・FAQ・歴史的経緯・参考文献までを 1 ページに集約し、 用語の「地図」として使えるようにしました。
関連用語(前提・並列・発展)と関連グループ教材も末尾にまとめてあるので、 用語の地図として活用してください。
連続最適化は、 決定変数が 連続実数 である最適化問題を扱う分野です。 「最小二乗で回帰係数を決める」「最尤推定でパラメータを当てはめる」「ニューラルネットの重みを学習する」のは、 すべて連続最適化問題です。
対比として 組合せ最適化は決定変数が 0/1 や順列などの離散値、 たとえば「都道府県をどの 3 クラスタに分けるか」のような問題を扱います。 連続最適化は微分・凸性という強力な道具立てが使えるため、 数値解法は概して洗練されています。
SSDSE の例で言えば、 「県内総生産を 人口、 就業者数、 大学数で説明する線形回帰」は、 47 個の県データに対する 4 個の連続パラメータの最適化問題です。
もっとも基本的な連続最適化問題は、 制約なし最小化:
$f$ が微分可能なら、 最適性条件 $\nabla f(\theta^\star) = 0$ の解を探す。
解の必要条件は KKT (Karush-Kuhn-Tucker) 条件:
代表的な数値解法:
連続最適化を支える概念を整理します。
| 概念 | 意味 | 例 |
|---|---|---|
| 目的関数 $f$ | 最小化/最大化する量 | 残差二乗和、 負対数尤度、 損失関数 |
| 決定変数 $\theta$ | 最適化される連続パラメータ | 回帰係数、 NN の重み |
| 制約 | $\theta$ が満たすべき式 | $\theta\ge 0$、 $\|\theta\|\le 1$ |
| 勾配 $\nabla f$ | 1 次の変化方向 | 各偏微分のベクトル |
| ヘッセ $\nabla^2 f$ | 2 次の曲率 | 正定値なら凸 |
| 凸性 | $f(\alpha x+(1-\alpha)y)\le \alpha f(x)+(1-\alpha)f(y)$ | 凸なら局所最適=大域最適 |
| ラグランジュ乗数 | 制約の影付き価格 | 制約緩和の感度 |
| 双対問題 | 主問題の下界を与える | SVM の双対形は内積で書ける |
SSDSE-B-2026 の 2023 年、 47 都道府県を使って $y$ = 県内総生産(C3301、 B 表に集約)、 $x$ = 総人口とする 1 次式 $y = a + b x$ の係数を最小二乗で求めます。 これは凸 2 次計画なので解析解があり、
$$b = rac{\sum (x_i-ar x)(y_i-ar y)}{\sum (x_i-ar x)^2},\quad a = ar y - b\,ar x$$実 SSDSE データでは、 $ar x pprox 264.6$ 万人、 $ar y pprox 11.7$ 兆円、 相関 r ≈ 0.97 で、 おおむね
この回帰問題は形式上、 凸 2 次計画 (QP) です。 制約を $b\ge 0$ と加えても閉形式は崩れますが、 KKT で解けます。
import numpy as np
from scipy.optimize import minimize
def rosenbrock(x):
return (1 - x[0])**2 + 100*(x[1] - x[0]**2)**2
res = minimize(rosenbrock, x0=[-1.2, 1.0], method='BFGS')
print(res.x, res.fun)
import pandas as pd, numpy as np
import cvxpy as cp
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis')
df.columns = df.iloc[0]
df = df.iloc[1:].reset_index(drop=True)
df = df[df['年度']=='2023'].reset_index(drop=True)
x = df['総人口'].astype(float).to_numpy()/1e6
y = df['県内総生産'].astype(float).to_numpy()/1e12 # 兆円
n = len(x)
X = np.column_stack([np.ones(n), x])
beta = cp.Variable(2)
obj = cp.Minimize(cp.sum_squares(X @ beta - y))
cons = [beta[1] >= 0] # 「傾きは非負」という制約
prob = cp.Problem(obj, cons)
prob.solve()
print('係数:', beta.value, '残差^2:', prob.value)
from sklearn.linear_model import Ridge
X_full = df[['総人口','15歳未満人口','15〜64歳人口','65歳以上人口']].astype(float).to_numpy()
model = Ridge(alpha=1.0)
model.fit(X_full, df['県内総生産'].astype(float))
print('回帰係数:', model.coef_)
print('切片:', model.intercept_)
import numpy as np
x = df['総人口'].astype(float).to_numpy()/1e6
y = df['県内総生産'].astype(float).to_numpy()/1e12
X = np.column_stack([np.ones_like(x), x])
theta = np.zeros(2)
eta = 1e-3
for k in range(2000):
grad = X.T @ (X @ theta - y) / len(y)
theta -= eta * grad
print('GD 解:', theta)
最小二乗問題:
$$\min_\beta \|y - X\beta\|^2 \quad\Leftrightarrow\quad \beta^\star = (X^\top X)^{-1} X^\top y$$これは凸 2 次計画 (QP) で、 解析解が存在します。
負の対数尤度を最小化:
$$\min_\beta \sum_i \log(1 + e^{-y_i X_i \beta})$$勾配は閉形ではないが凸なので、 Newton-Raphson や IRLS で大域最適に収束。
$\|\cdot\|_1$ が非滑らかなので、 座標降下法・近接勾配法 (ISTA/FISTA) を使う。
重み $W$ について損失 $L(W)$ が高度に非凸。 Adam・AdamW・SGD with momentum が標準。 局所最適より サドル点が問題 という研究もある。
import pandas as pd, numpy as np
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis')
df.columns = df.iloc[0]
df = df.iloc[1:].reset_index(drop=True)
df = df[df['年度']=='2023'].reset_index(drop=True)
X = df[['総人口']].astype(float).to_numpy() / 1e6
y = df['県内総生産'].astype(float).to_numpy() / 1e12
X = np.hstack([np.ones_like(X), X])
theta = np.zeros(2)
for k in range(5000):
grad = X.T @ (X @ theta - y) / len(y)
theta -= 0.005 * grad
if k % 1000 == 0:
loss = ((X @ theta - y) ** 2).mean()
print(f'iter {k}: loss={loss:.4f}, theta={theta}')
ステップ 1:問題設定
$y$ = 県内総生産(兆円)、 $x_1$ = 総人口(百万人)、 $x_2$ = 65歳以上人口割合(%)。 回帰モデル $y = \beta_0 + \beta_1 x_1 + \beta_2 x_2$。 「$\beta_1$(人口係数)は非負」 という業務制約を加える。
ステップ 2:cvxpy で定式化
import pandas as pd, numpy as np
import cvxpy as cp
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis')
df.columns = df.iloc[0]
df = df.iloc[1:].reset_index(drop=True)
df = df[df['年度']=='2023'].reset_index(drop=True)
df['総人口'] = df['総人口'].astype(int)
df['65歳以上人口'] = df['65歳以上人口'].astype(int)
df['県内総生産'] = df['県内総生産'].astype(int)
df['65歳以上比率'] = df['65歳以上人口'] / df['総人口'] * 100
n = len(df)
X = np.column_stack([np.ones(n),
df['総人口'].to_numpy()/1e6,
df['65歳以上比率'].to_numpy()])
y = df['県内総生産'].to_numpy()/1e12
beta = cp.Variable(3)
obj = cp.Minimize(cp.sum_squares(X @ beta - y))
cons = [beta[1] >= 0, beta[1] <= 10] # 業務知識からの制約
prob = cp.Problem(obj, cons)
prob.solve()
print('係数:', beta.value)
print('残差二乗和:', prob.value)
ステップ 3:KKT 条件の確認
grad = 2 * X.T @ (X @ beta.value - y)
# beta[1] が制約境界に当たっていれば、 対応するラグランジュ乗数 > 0
for i, c in enumerate(cons):
print(f'制約 {i} 双対変数:', c.dual_value)
ステップ 4:制約あり vs なし比較
unc, *_ = np.linalg.lstsq(X, y, rcond=None)
print('無制約解:', unc)
print('制約解:', beta.value)
# 残差・予測精度・解釈を比較
ステップ 5:感度分析
各係数を ±10% 動かしたときの残差変化を計算。 ラグランジュ乗数は「制約を 1 単位緩めたときの目的改善」を示す。
$\min_\theta L(\theta)$ — 損失 $L$ を連続パラメータ $\theta$ について最小化。 線形回帰・ロジスティック・SVM・NN すべて。
Markowitz の平均-分散最適化。 凸 QP。 制約付き SSDSE 県別投資配分にも応用可。
$\hat\theta = \arg\max \log p(D|\theta)$ — 統計推定の中核は連続最適化。
REINFORCE、 PPO、 SAC — 報酬期待値を最大化する連続パラメータ最適化。
勾配ベース NAS(DARTS)は連続最適化として定式化。
LQR・MPC — 二次形コスト最小化の連続制御。 自動運転・ロボット制御。
建築・機械部品の質量最小化、 強度制約付き。 SQP / 内点法。
発電配分の凸最適化。 LP / QP / 確率計画。
| 手法 | 必要情報 | 収束 | 適用 |
|---|---|---|---|
| 勾配降下 | 1 次勾配 | 線形 | NN, 大規模 SGD |
| Newton-Raphson | 1+2 次 | 2 次 | 低次元、 凸 |
| BFGS / L-BFGS | 1 次のみ | 準 2 次 | 中次元、 凸 |
| 共役勾配 | 1 次 | 準 2 次 | 巨大スパース |
| 内点法 | 1+2 次 | 多項式時間 | LP / QP / SDP |
| シンプレックス | 線形構造 | 有限 | LP |
| Adam | 1 次 + 履歴 | 準 1 次 | NN |
| SGD with momentum | 1 次 + 慣性 | 確率的 | NN, 大規模 |
| 近接勾配 (ISTA) | 1 次 + 近接 | 線形 | LASSO |
| 用語 | 意味 |
|---|---|
| 目的関数 | 最小化/最大化する関数 |
| 決定変数 | 最適化する変数 |
| 制約 | 変数が満たすべき条件 |
| 勾配 | 関数の 1 階偏微分ベクトル |
| ヘッセ | 2 階偏微分行列 |
| 凸関数 | 局所最適 = 大域最適となる関数 |
| KKT 条件 | 制約付き最適性の必要条件 |
| ラグランジュ乗数 | 制約の影付き価格 |
| 双対問題 | 主問題の下界を与える別問題 |
| Newton 法 | 2 次情報を使う反復法 |
| 勾配降下 | 1 次情報のみで進む反復法 |
| Adam | モメンタム + 適応学習率の SGD 系 |
| レシピ | コード |
|---|---|
| scipy.optimize.minimize | from scipy.optimize import minimize res = minimize(f, x0, method='BFGS') |
| 勾配を渡す | minimize(f, x0, jac=grad_f, method='Newton-CG') |
| ヘッセを渡す | minimize(f, x0, jac=grad_f, hess=hess_f, method='trust-ncg') |
| 制約付き | minimize(f, x0, constraints=[{'type':'ineq', 'fun': g}]) |
| 境界付き | minimize(f, x0, bounds=[(0,1),(0,5)], method='L-BFGS-B') |
| cvxpy 凸最適化 | import cvxpy as cp x = cp.Variable(); prob = cp.Problem(cp.Minimize(cp.square(x-3))); prob.solve() |
| 最小二乗解析解 | beta, *_ = np.linalg.lstsq(X, y, rcond=None) |
| Ridge | from sklearn.linear_model import Ridge Ridge(alpha=1.0).fit(X, y) |
| Lasso | from sklearn.linear_model import Lasso Lasso(alpha=0.1).fit(X, y) |
| LogisticRegression | from sklearn.linear_model import LogisticRegression LogisticRegression().fit(X, y) |
| ロス関数勾配の自動微分 | import jax; grad_f = jax.grad(f) |
| PyTorch Adam | opt = torch.optim.Adam(model.parameters(), lr=1e-3) |
| SciPy linprog (LP) | from scipy.optimize import linprog res = linprog(c, A_ub=A, b_ub=b) |
| 基底ニュートン法 | for k in range(N):
x -= np.linalg.solve(hess_f(x), grad_f(x)) |
| 収束判定 | if np.linalg.norm(grad) < tol: break |
歴史と位置づけ:連続最適化は 17 世紀の微積分(Newton, Leibniz)にまで遡りますが、 現代的な体系化は 20 世紀。 主な節目:
機械学習・統計の 学習は事実上すべて連続最適化問題で、 損失関数の最小化として定式化されます。 凸最適化(Boyd & Vandenberghe, 2004)は本分野の標準教科書。
連続最適化を中心とした「学習=最適化」の構図:
[損失/負尤度]─ 最小化 ─► [パラメータ]
▲ │
│ ▼
[データ]──────────► [勾配/ヘッセ]
│
▼
(勾配降下/ニュートン/BFGS/SGD/Adam)
凸 ←─ 線形回帰・ロジスティック・SVM(線形)・LASSO・Ridge ─→ 大域最適
非凸 ←─ NN・混合モデル・EM・GAN ─→ 局所最適 + 複数初期値