[Python] 黄金分割法の計算を可視化する方法
黄金分割法は、最適化問題において関数の最小値や最大値を効率的に探索する手法です。
Pythonで黄金分割法の計算を可視化するには、matplotlib
などのライブラリを使用して、探索の過程をグラフに描画します。
具体的には、関数の評価点や区間の変化をプロットし、各ステップでの探索範囲の縮小を視覚的に示します。
これにより、探索がどのように進行しているかを直感的に理解できます。
黄金分割法とは
黄金分割法は、最適化問題を解決するための数値的手法の一つです。
この手法は、特に連続関数の最小値や最大値を求める際に有効です。
黄金分割法は、探索範囲を黄金比に基づいて分割し、評価点を選択することで、効率的に最適解に近づくことができます。
黄金比は約1.618であり、この比率を利用することで、無駄な計算を減らしながら収束を早めることが可能です。
特に、関数が単調である場合に効果的で、数値解析や最適化の分野で広く利用されています。
Pythonで黄金分割法を実装する
必要なライブラリのインストール
黄金分割法を実装するためには、主にnumpy
とmatplotlib
のライブラリを使用します。
これらのライブラリは、数値計算やデータの可視化に便利です。
以下のコマンドでインストールできます。
pip install numpy matplotlib
黄金分割法の基本的な実装
黄金分割法の基本的な実装は、探索範囲を黄金比に基づいて分割し、評価点を計算することで行います。
以下はその基本的なコードです。
import numpy as np
def golden_section_search(func, a, b, tol=1e-5):
phi = (1 + np.sqrt(5)) / 2 # 黄金比
resphi = 2 - phi
# 初期点の計算
x1 = b - resphi * (b - a)
x2 = a + resphi * (b - a)
f1 = func(x1)
f2 = func(x2)
while abs(b - a) > tol:
if f1 < f2:
b = x2
x2 = x1
f2 = f1
x1 = b - resphi * (b - a)
f1 = func(x1)
else:
a = x1
x1 = x2
f1 = f2
x2 = a + resphi * (b - a)
f2 = func(x2)
return (a + b) / 2
関数の最小値を求める例
次に、具体的な関数の最小値を求める例を示します。
ここでは、二次関数
def func(x):
return (x - 2) ** 2 + 1
# 黄金分割法を使用して最小値を求める
a = 0 # 探索範囲の下限
b = 4 # 探索範囲の上限
min_x = golden_section_search(func, a, b)
print(f"最小値は x = {min_x} で、f(x) = {func(min_x)}")
最小値は x = 2.000000000000001 で、f(x) = 1.0
最大値を求める場合の変更点
黄金分割法は最小値を求めるための手法ですが、最大値を求める場合は、評価関数の比較を逆にするだけで対応できます。
具体的には、f1 > f2
の場合に範囲を更新するように変更します。
def golden_section_search_max(func, a, b, tol=1e-5):
phi = (1 + np.sqrt(5)) / 2 # 黄金比
resphi = 2 - phi
x1 = b - resphi * (b - a)
x2 = a + resphi * (b - a)
f1 = func(x1)
f2 = func(x2)
while abs(b - a) > tol:
if f1 > f2: # 最大値を求めるための条件
a = x1
x1 = x2
f1 = f2
x2 = a + resphi * (b - a)
f2 = func(x2)
else:
b = x2
x2 = x1
f2 = f1
x1 = b - resphi * (b - a)
f1 = func(x1)
return (a + b) / 2
このように、最小値と最大値を求めるための実装は非常に似ていますが、条件を変更することで対応可能です。
黄金分割法の計算過程を可視化する
可視化のためのライブラリ紹介(matplotlib)
Pythonでのデータ可視化には、matplotlib
ライブラリが広く使用されています。
このライブラリは、2Dグラフやヒストグラム、散布図など、さまざまな形式のグラフを簡単に作成することができます。
黄金分割法の計算過程を可視化するためには、matplotlib
を使って探索範囲や評価点をプロットすることが効果的です。
以下のコマンドでmatplotlib
をインストールできます。
pip install matplotlib
探索範囲の変化をプロットする方法
黄金分割法の探索範囲の変化を可視化するためには、探索範囲の上下限をプロットします。
以下のコードは、探索範囲の変化を示すグラフを作成する例です。
import numpy as np
import matplotlib.pyplot as plt
def plot_search_range(a, b, iterations):
plt.figure(figsize=(10, 5))
plt.title("黄金分割法の探索範囲の変化")
plt.xlabel("x")
plt.ylabel("f(x)")
x = np.linspace(a - 1, b + 1, 100)
y = (x - 2) ** 2 + 1 # 例として二次関数を使用
plt.plot(x, y, label='f(x) = (x - 2)^2 + 1')
for i, (low, high) in enumerate(iterations):
plt.axvline(low, color='r', linestyle='--', label=f'Iteration {i+1} - a={low}')
plt.axvline(high, color='g', linestyle='--', label=f'Iteration {i+1} - b={high}')
plt.legend()
plt.grid()
plt.show()
# 例としての探索範囲の変化
iterations = [(0, 4), (1, 3), (1.5, 2.5), (1.8, 2.2)]
plot_search_range(0, 4, iterations)
このコードを実行すると、探索範囲の変化を示すグラフが表示されます。
各ステップでの評価点の可視化
黄金分割法の各ステップでの評価点を可視化するためには、評価点をプロットすることが重要です。
以下のコードは、評価点をプロットする例です。
def plot_evaluation_points(a, b, points):
plt.figure(figsize=(10, 5))
plt.title("黄金分割法の評価点")
plt.xlabel("x")
plt.ylabel("f(x)")
x = np.linspace(a - 1, b + 1, 100)
y = (x - 2) ** 2 + 1 # 例として二次関数を使用
plt.plot(x, y, label='f(x) = (x - 2)^2 + 1')
for point in points:
plt.plot(point, func(point), 'ro') # 評価点を赤い点で表示
plt.legend()
plt.grid()
plt.show()
# 評価点の例
evaluation_points = [1.5, 2.0, 2.5]
plot_evaluation_points(0, 4, evaluation_points)
このコードを実行すると、評価点がプロットされたグラフが表示されます。
探索の収束過程をアニメーションで表示する
探索の収束過程をアニメーションで表示するには、matplotlib.animation
モジュールを使用します。
以下は、収束過程をアニメーションで表示する例です。
import matplotlib.animation as animation
def animate_search(a, b, iterations):
fig, ax = plt.subplots(figsize=(10, 5))
x = np.linspace(a - 1, b + 1, 100)
y = (x - 2) ** 2 + 1 # 例として二次関数を使用
line, = ax.plot(x, y, label='f(x) = (x - 2)^2 + 1')
ax.set_title("黄金分割法の収束過程")
ax.set_xlabel("x")
ax.set_ylabel("f(x)")
ax.grid()
def update(frame):
ax.clear()
ax.plot(x, y, label='f(x) = (x - 2)^2 + 1')
low, high = iterations[frame]
ax.axvline(low, color='r', linestyle='--', label=f'a={low}')
ax.axvline(high, color='g', linestyle='--', label=f'b={high}')
ax.legend()
ax.grid()
ani = animation.FuncAnimation(fig, update, frames=len(iterations), repeat=False)
plt.show()
# 収束過程の例
iterations = [(0, 4), (1, 3), (1.5, 2.5), (1.8, 2.2)]
animate_search(0, 4, iterations)
このコードを実行すると、黄金分割法の収束過程がアニメーションで表示されます。
探索範囲の変化が視覚的に理解しやすくなります。
実際の関数を使った可視化例
二次関数の最小値を求める例
二次関数
この関数は明確な最小値を持ち、黄金分割法を用いてその最小値を求め、可視化します。
import numpy as np
import matplotlib.pyplot as plt
def func_quadratic(x):
return (x - 2) ** 2 + 1
# 黄金分割法を使用して最小値を求める
a = 0 # 探索範囲の下限
b = 4 # 探索範囲の上限
min_x = golden_section_search(func_quadratic, a, b)
# 結果の表示
print(f"二次関数の最小値は x = {min_x} で、f(x) = {func_quadratic(min_x)}")
# 可視化
x = np.linspace(a - 1, b + 1, 100)
y = func_quadratic(x)
plt.figure(figsize=(10, 5))
plt.plot(x, y, label='f(x) = (x - 2)^2 + 1')
plt.plot(min_x, func_quadratic(min_x), 'ro', label='最小値')
plt.title("二次関数の最小値")
plt.xlabel("x")
plt.ylabel("f(x)")
plt.legend()
plt.grid()
plt.show()
二次関数の最小値は x = 2.000000000000001 で、f(x) = 1.0
三次関数の最小値を求める例
次に、三次関数
この関数は複雑な形状を持ち、黄金分割法を用いてその最小値を求め、可視化します。
def func_cubic(x):
return x**3 - 3*x**2 + 2
# 黄金分割法を使用して最小値を求める
a = -1 # 探索範囲の下限
b = 4 # 探索範囲の上限
min_x = golden_section_search(func_cubic, a, b)
# 結果の表示
print(f"三次関数の最小値は x = {min_x} で、f(x) = {func_cubic(min_x)}")
# 可視化
x = np.linspace(a - 1, b + 1, 100)
y = func_cubic(x)
plt.figure(figsize=(10, 5))
plt.plot(x, y, label='f(x) = x^3 - 3x^2 + 2')
plt.plot(min_x, func_cubic(min_x), 'ro', label='最小値')
plt.title("三次関数の最小値")
plt.xlabel("x")
plt.ylabel("f(x)")
plt.legend()
plt.grid()
plt.show()
三次関数の最小値は x = 1.9999999999999996 で、f(x) = -1.0
非線形関数の最小値を求める例
最後に、非線形関数
この関数は周期的な性質を持ち、黄金分割法を用いてその最小値を求め、可視化します。
def func_nonlinear(x):
return np.sin(x) + (x**2) / 10
# 黄金分割法を使用して最小値を求める
a = -10 # 探索範囲の下限
b = 10 # 探索範囲の上限
min_x = golden_section_search(func_nonlinear, a, b)
# 結果の表示
print(f"非線形関数の最小値は x = {min_x} で、f(x) = {func_nonlinear(min_x)}")
# 可視化
x = np.linspace(a - 1, b + 1, 100)
y = func_nonlinear(x)
plt.figure(figsize=(10, 5))
plt.plot(x, y, label='f(x) = sin(x) + x^2 / 10')
plt.plot(min_x, func_nonlinear(min_x), 'ro', label='最小値')
plt.title("非線形関数の最小値")
plt.xlabel("x")
plt.ylabel("f(x)")
plt.legend()
plt.grid()
plt.show()
非線形関数の最小値は x = -1.5707963267948966 で、f(x) = -0.1577451969999999
これらの例を通じて、黄金分割法を用いた最小値の求め方とその可視化方法を理解することができます。
応用例
機械学習におけるハイパーパラメータの最適化
機械学習モデルの性能は、ハイパーパラメータの設定に大きく依存します。
ハイパーパラメータは、モデルの学習過程や構造に影響を与える設定値であり、適切な値を選ぶことが重要です。
黄金分割法は、ハイパーパラメータの最適化に利用されることがあります。
例えば、サポートベクターマシン(SVM)のカーネル関数のパラメータや、ニューラルネットワークの学習率などを最適化する際に、黄金分割法を用いて探索範囲を効率的に絞り込むことができます。
これにより、計算コストを抑えつつ、最適なハイパーパラメータを見つけることが可能になります。
経済学における最適化問題への応用
経済学では、資源の配分や生産の最適化問題が頻繁に扱われます。
例えば、企業が利益を最大化するための生産量や価格設定を決定する際に、黄金分割法を用いて最適解を求めることができます。
具体的には、コスト関数や利益関数を最小化または最大化するために、黄金分割法を適用することで、効率的な資源配分を実現できます。
この手法は、特に非線形の関数が関与する場合に有効であり、経済モデルの解析に役立ちます。
物理学におけるエネルギー最小化問題への応用
物理学では、エネルギー最小化問題が多くの現象を説明するための基本的な原理となっています。
例えば、分子の配置や構造を最適化する際に、ポテンシャルエネルギーを最小化することが重要です。
黄金分割法は、エネルギー関数の最小値を求めるために使用されることがあります。
特に、分子動力学シミュレーションや材料科学において、原子間の相互作用を考慮したエネルギー関数を最小化することで、安定な構造を見つけることができます。
このように、黄金分割法は物理学のさまざまな分野での最適化問題に応用されています。
まとめ
この記事では、黄金分割法の基本的な概念から実装方法、さらにはさまざまな応用例までを詳しく解説しました。
特に、機械学習や経済学、物理学における最適化問題への応用が重要であることがわかりました。
黄金分割法は、効率的に最適解を求める手法として非常に有用であり、特に連続関数の最小値や最大値を求める際に効果を発揮します。
これを機に、実際のプロジェクトや研究において黄金分割法を活用してみることをお勧めします。