線形最適化問題 CVXPY

線形最適化問題

CVXPYを使用して、簡単な線形最適化問題を解いてみましょう。

ここでは、2つの変数を持つ最小化の線形関数を扱います。例として、次のような問題を解いてみます。

$$
\text{minimize} \quad 3x + 4y
$$
$$
\text{subject to} \quad x + 2y \geq 10
$$
$$
\text{subject to} \quad 3x - y \leq 12
$$
$$
\text{subject to} \quad x, y \geq 0
$$

以下がそのコードです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

# 変数を定義
x = cp.Variable()
y = cp.Variable()

# 目的関数と制約条件を定義
objective = cp.Minimize(3*x + 4*y)
constraints = [x + 2*y >= 10, 3*x - y <= 12, x >= 0, y >= 0]

# 最適化問題の定義
problem = cp.Problem(objective, constraints)

# 問題を解く
problem.solve()

# 最適な解の表示
print("Optimal value:", problem.value)
print("x =", x.value)
print("y =", y.value)

# グラフ描画
x_values = np.linspace(0, 10, 100)
y1_values = (10 - x_values) / 2
y2_values = 3 * x_values - 12

plt.figure(figsize=(6, 6))
plt.plot(x_values, y1_values, label='x + 2y >= 10')
plt.plot(x_values, y2_values, label='3x - y <= 12')
plt.fill_between(x_values, np.maximum(0, y1_values), np.minimum(10, (12 + y2_values) / 3), color='gray', alpha=0.3)
plt.plot(x.value, y.value, 'ro') # 最適解のプロット
plt.xlabel('x')
plt.ylabel('y')
plt.title('Optimization with CVXPY')
plt.legend()
plt.grid(True)
plt.show()

これにより、線形最適化問題が解かれ、最適解が計算されます。

また、制約条件最適解が含まれたグラフも描画されます。

この場合、最適解は赤い点で示されます。

ソースコード解説

このコードは、CVXPYを使用して線形最適化問題を解決し、結果をグラフで視覚化するものです。

1. 必要なライブラリのインポート

1
2
3
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

必要なライブラリ(CVXPY、NumPy、Matplotlib)をインポートします。

2. 変数の定義

1
2
x = cp.Variable()
y = cp.Variable()

最適化問題で使用する変数 xy を定義しています。

3. 目的関数と制約条件の設定

1
2
objective = cp.Minimize(3*x + 4*y)
constraints = [x + 2*y >= 10, 3*x - y <= 12, x >= 0, y >= 0]

最小化したい目的関数制約条件を設定しています。

この場合、目的関数は$ (3x + 4y) $で、制約条件は不等式制約です。

4. 最適化問題の定義

1
problem = cp.Problem(objective, constraints)

CVXPYの Problem クラスを使って最適化問題を定義しています。

目的関数制約条件を引数として渡しています。

5. 問題の解決

1
problem.solve()

定義した最適化問題を解いています。
CVXPYが問題を解くための適切な最適化アルゴリズムを選択し、最適な解を見つけようとします。

6. 最適な解の表示

1
2
3
print("Optimal value:", problem.value)
print("x =", x.value)
print("y =", y.value)

最適な目的関数の値とそれに対する最適な変数 xy の値を表示しています。

7. グラフの描画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
x_values = np.linspace(0, 10, 100)
y1_values = (10 - x_values) / 2
y2_values = 3 * x_values - 12

plt.figure(figsize=(6, 6))
plt.plot(x_values, y1_values, label='x + 2y >= 10')
plt.plot(x_values, y2_values, label='3x - y <= 12')
plt.fill_between(x_values, np.maximum(0, y1_values), np.minimum(10, (12 + y2_values) / 3), color='gray', alpha=0.3)
plt.plot(x.value, y.value, 'ro') # 最適解のプロット
plt.xlabel('x')
plt.ylabel('y')
plt.title('Optimization with CVXPY')
plt.legend()
plt.grid(True)
plt.show()

制約条件をグラフにプロットし、最適な解を赤い点として表示しています。

fill_between制約条件の領域を色で塗りつぶし、plt.plot最適解を赤い点でプロットしています。

結果解説

この結果は、与えられた線形最適化問題の最適な解を示しています。
最適な目的関数の値は約20です。

最適解は、$ (x \approx 0) $および$ (y \approx 5) $です。
つまり、制約条件を満たしながら最適な解が見つかりました。

グラフは、制約条件を表しています。
青い線はそれぞれ制約条件を示し、グレーの領域はすべての制約条件を満たす領域を示しています。
赤い点は最適解を表しており、制約条件の交差点に位置しています。
つまり、目的関数を最小化するための最適な$ (x) と (y) $の値を示しています。

最適解が$ (x \approx 0) $となる理由は、制約条件 $ (3x - y \leq 12) $により、$ (x) $が増加すると$ (y) $も増加する必要があるためです。
この条件を満たしつつ、目的関数を最小化するためには$ (x) $を極小化し$ (y) $を最大化するのが最適な戦略であり、その結果、$ (x \approx 0) $となります。

Bin Packing Problem(ビンパッキング問題) PuLP

Bin Packing Problem(ビンパッキング問題)

Bin Packing Problem(ビンパッキング問題)という問題をPythonで解く例を示します。

ビンパッキング問題とはビン(容器)に物を詰める最適化問題で、ここでは2つの容器に5つのアイテムを詰める例を示します。

まず、必要なライブラリをインストールします:

1
pip install pulp

以下のPythonコードは、このビンパッキング問題を解くためのものです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pulp import *

# ビンの数とアイテムの数を設定
bin_count = 2
item_count = 5

# 各ビンの容量、アイテムの重さを設定
bin_capacity = [10, 10]
item_weight = [2, 5, 4, 7, 1]

# 問題設定
prob = LpProblem("BinPacking", LpMinimize)

# アイテムをビンに入れるかどうかを示すノードを作成(バイナリ変数)
x = [[LpVariable("x(%s,%s)" % (i, j), cat="Binary") for j in range(item_count)] for i in range(bin_count)]

# 目的関数: 使用するビンの数を最小化する
prob += lpSum(x[i][j] for i in range(bin_count) for j in range(item_count))

# 制約条件: 各アイテムは1つのビンにしか入らない
for j in range(item_count):
prob += lpSum(x[i][j] for i in range(bin_count)) == 1

# 制約条件: 各ビンの容量を超えてアイテムを入れられない
for i in range(bin_count):
prob += lpSum(item_weight[j] * x[i][j] for j in range(item_count)) <= bin_capacity[i]

# 最適化計算
prob.solve()

# 結果表示
for i in range(bin_count):
print("*****Bin", i, "*****")
total_weight = 0
for j in range(item_count):
if value(x[i][j])==1:
print("Item", j)
total_weight+=item_weight[j]
print("Total weight:", total_weight)

このコードでは2つのビンに5つのアイテムを最適に配置しています。

出力結果は各ビンに収められたアイテムとその合計重量を表示します。

[実行結果]

*****Bin 0 *****
Item 1
Item 2
Total weight: 9
*****Bin 1 *****
Item 0
Item 3
Item 4
Total weight: 10

ソースコード解説

このコードは、Bin Packing Problem(ビンパッキング問題)を解くためにPuLP(Pythonの最適化モデリングライブラリ)を使用しています。

1. 必要なライブラリのインポート

1
from pulp import *

PuLPからすべての関数をインポートしています。

2. 問題のパラメータ設定

1
2
3
4
bin_count = 2
item_count = 5
bin_capacity = [10, 10]
item_weight = [2, 5, 4, 7, 1]

ビンの数やアイテムの数、各ビンの容量、アイテムの重さを設定しています。

3. 問題の設定

1
prob = LpProblem("BinPacking", LpMinimize)

PuLPを使って「BinPacking」という名前の最小化問題を定義しています。

4. 変数の定義

1
x = [[LpVariable("x(%s,%s)" % (i, j), cat="Binary") for j in range(item_count)] for i in range(bin_count)]

ビンにアイテムを入れるかどうかを示す変数 xバイナリ変数として定義しています。

5. 目的関数の設定

1
prob += lpSum(x[i][j] for i in range(bin_count) for j in range(item_count))

使用するビンの数を最小化する目的関数を定義しています。

6. 制約条件の設定

1
2
3
4
5
for j in range(item_count):
prob += lpSum(x[i][j] for i in range(bin_count)) == 1

for i in range(bin_count):
prob += lpSum(item_weight[j] * x[i][j] for j in range(item_count)) <= bin_capacity[i]

各アイテムが1つのビンにしか入らない制約条件と、各ビンの容量を超えない制約条件を設定しています。

7. 最適化計算

1
prob.solve()

PuLPを使って最適化問題を解いています。

8. 結果表示

1
2
3
4
5
6
7
8
for i in range(bin_count):
print("*****Bin", i, "*****")
total_weight = 0
for j in range(item_count):
if value(x[i][j])==1:
print("Item", j)
total_weight+=item_weight[j]
print("Total weight:", total_weight)

最適化計算の結果を表示しており、各ビンに入ったアイテムとその総重量を出力しています。

株価予測 Prophet

株価予測

株価の予測を行ってみましょう。

Prophetを使用して株価の未来予測を行うことが可能です。

以下は、仮想の株価データを用いてProphetを使った株価予測の例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import pandas as pd
import numpy as np
from prophet import Prophet
import matplotlib.pyplot as plt

# ランダムな株価データを生成
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', periods=365, freq='D')
prices = np.cumsum(np.random.randn(365)) + 100 # ランダムな価格変動

data = {
'ds': dates,
'y': prices
}

df = pd.DataFrame(data)

# Prophetモデルの作成と学習
model = Prophet()
model.fit(df)

# 予測用データの作成
future = model.make_future_dataframe(periods=30) # 30日間の予測
forecast = model.predict(future)

# 予測結果をグラフ化
fig = model.plot(forecast)
plt.xlabel('Date')
plt.ylabel('Stock Price')
plt.title('Random Stock Price Forecast')
plt.show()

この例では、乱数を使って生成したランダムな価格変動を持つ株価データを作成し、Prophetモデルを使って未来30日間の株価を予測しています。

生成されたランダムなデータを用いているため、実際の株価とは関係ありませんが、Prophetがこのようなデータでも時系列の予測を行うことができることを示しています。

ソースコード解説

このソースコードは、PythonのPandas、NumPy、Prophet(Facebookが提供する時系列データの予測ライブラリ)、Matplotlibを使用して、ランダムな株価データを生成し、Prophetモデルを使って未来の株価を予測し、その結果をグラフ化しています。

1. ランダムな株価データの生成

1
2
3
4
5
6
7
8
9
10
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', periods=365, freq='D')
prices = np.cumsum(np.random.randn(365)) + 100 # ランダムな価格変動

data = {
'ds': dates,
'y': prices
}

df = pd.DataFrame(data)

この部分では、np.random.seed(42)で乱数のシードを設定し、365日分の日付とランダムな株価のデータを生成しています。
これらのデータを'ds'(日付)と'y'(株価)のカラムを持つPandasのDataFrameに格納しています。

2. Prophetモデルの作成と学習

1
2
model = Prophet()
model.fit(df)

Prophetのモデルを作成し、fit()メソッドを使ってデータを学習させています。
Prophetは時系列データの予測に特化したモデルで、ここでは与えられた株価データを元にモデルを構築しています。

3. 予測用データの作成と予測

1
2
future = model.make_future_dataframe(periods=30)  # 30日間の予測
forecast = model.predict(future)

make_future_dataframe()メソッドを使って、元のデータから未来の30日間の日付を含むDataFrameを作成しています。
それを使ってpredict()メソッドで予測を行い、forecastに未来の予測結果を格納しています。

4. 予測結果をグラフ化

1
2
3
4
5
fig = model.plot(forecast)
plt.xlabel('Date')
plt.ylabel('Stock Price')
plt.title('Random Stock Price Forecast')
plt.show()

最後の部分では、plot()メソッドを使って予測結果をグラフ化しています。
横軸には日付縦軸には株価が表示され、予測されたデータに対する実際のデータと予測の境界が示されています。
これにより、モデルが学習した過去のデータに対する予測未来の予測の推移が視覚化されます。

結果解説

このグラフは、Prophetによる株価の予測を示しています。
横軸は日付を示し、縦軸は株価を表しています。

以下はグラフの要素についての詳細です。

1. 黒色の点:

グラフ上の黒色の点は、実際の株価データを表しています。
過去の実際のデータポイントがこの線上にプロットされています。

2. 青色の線:

青色の線は、過去の実際のデータポイントに対するProphetモデルの適合を表しています。
点線が黒色の点に密着しているほど、モデルが過去のデータをよく予測できていることを示します。

3. 青色の領域:

青色の線の周囲には、淡い青色の領域があります。
これは予測区間を表しており、将来の株価の変動がこの領域内に含まれる可能性を示しています。
通常、時間が経つにつれてこの領域が広がる傾向があります。

このグラフ全体を通じて、過去の実際のデータに対するモデルの適合度未来の予測値が視覚的に表現されています。

モデルが過去のデータに適合し、予測区間が示されていることで、将来の株価の予測に対する確信度不確実性を示すことができます。

プロジェクトスケジューリング問題 NetworkX

プロジェクトスケジューリング問題

プロジェクトスケジューリング問題は、タスクの完了時間リソースの最適な割り当てを計画する問題です。

具体的な例として、4つのタスクとそれらの間の依存関係があるとしましょう。

  • Task A: 5日かかる
  • Task B: 3日かかる、Task A完了後に開始可能
  • Task C: 2日かかる、Task A完了後に開始可能
  • Task D: 4日かかる、Task BとTask C完了後に開始可能

これをPythonで解決してみましょう。

ここではnetworkxライブラリを使用してグラフを作成し、トポロジカルソートを行います。

まず、networkxをインストールします。

1
!pip install networkx

次に、Pythonコードで問題を解決します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import networkx as nx
import matplotlib.pyplot as plt

# グラフの作成
G = nx.DiGraph()

# タスクの追加
tasks = {
'A': {'duration': 5},
'B': {'duration': 3},
'C': {'duration': 2},
'D': {'duration': 4}
}

# タスク間の依存関係を追加
dependencies = [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D')]

# グラフにタスクと依存関係を追加
for task, data in tasks.items():
G.add_node(task, duration=data['duration'])

for dependency in dependencies:
G.add_edge(dependency[0], dependency[1])

# トポロジカルソート
schedule = list(nx.topological_sort(G))

# タスクのスケジュール表示
print("スケジュール:")
for i, task in enumerate(schedule):
print(f"Day {i + 1}: Task {task}")

# グラフの描画
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True, node_size=800, node_color='skyblue', font_weight='bold', font_size=12, edge_color='gray', arrowsize=20)
plt.title('Project Scheduling')
plt.show()

このコードは、依存関係を持つタスクをグラフで表現し、トポロジカルソートを使ってスケジュールを作成します。

そして、タスクのスケジュールを表示し、グラフを描画します。

ソースコード解説

このコードは、Pythonのnetworkxmatplotlibライブラリを使用してプロジェクトスケジュールを計画し、グラフで可視化するものです。

以下にコードの詳細を説明します:

1. ライブラリのインポート

1
2
import networkx as nx
import matplotlib.pyplot as plt
  • networkxはグラフの作成や操作、アルゴリズムの実行などをサポートするライブラリです。
  • matplotlib.pyplotはグラフを描画するためのライブラリです。

2. グラフの作成

1
G = nx.DiGraph()
  • DiGraph()関数を使って有向グラフを作成しています。

3. タスクの定義

1
2
3
4
5
6
tasks = {
'A': {'duration': 5},
'B': {'duration': 3},
'C': {'duration': 2},
'D': {'duration': 4}
}
  • タスクとその所要時間を辞書形式で定義しています。

4. タスク間の依存関係の定義

1
dependencies = [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D')]
  • タスク間の依存関係をタプルのリストとして定義しています。

5. グラフにタスクと依存関係を追加

1
2
3
4
5
for task, data in tasks.items():
G.add_node(task, duration=data['duration'])

for dependency in dependencies:
G.add_edge(dependency[0], dependency[1])
  • タスクとその所要時間をグラフにノードとして追加し、タスク間の依存関係をエッジとして追加しています。

6. トポロジカルソート

1
schedule = list(nx.topological_sort(G))
  • topological_sort()関数を使って、トポロジカルソートを行い、タスクのスケジュールを計画します。

7. タスクのスケジュール表示

1
2
3
print("スケジュール:")
for i, task in enumerate(schedule):
print(f"Day {i + 1}: Task {task}")
  • タスクのスケジュールをコンソールに出力します。

8. グラフの描画

1
2
3
4
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True, node_size=800, node_color='skyblue', font_weight='bold', font_size=12, edge_color='gray', arrowsize=20)
plt.title('Project Scheduling')
plt.show()
  • spring_layout()関数でノードの位置を計算し、draw()関数でグラフを描画しています。
  • 各ノードはタスクを表し、エッジはタスク間の依存関係を示しています。

これにより、プロジェクトのタスクとその依存関係をグラフで視覚化し、トポロジカルソートによってスケジュールを立てています。

結果解説

この結果は、与えられたタスクとその依存関係に基づいて計画されたスケジュールを示しています。

それぞれのタスクが実行される日数と順序は以下のようになっています:

  • Day 1: Task A
  • Day 2: Task B
  • Day 3: Task C
  • Day 4: Task D

それぞれのタスクの日数に加え、依存関係がスケジュールに影響を与えています。
Task Aは最初に実行され、その後、Task BTask Cがそれぞれ独立して実行されます。
最後に、Task BとTask Cの完了後にTask Dが実行されます。

グラフを見ると、各タスクがノードとして表され、依存関係が矢印で示されています。
このグラフは、タスク間の依存関係を視覚化し、トポロジカルソートによってタスクの実行順序が決定されました。
それにより、各タスクの開始と終了時期が特定されました。

非線形最適化問題 CVXPY

非線形最適化問題

以下のような非線形最適化問題を考えてみましょう。

例題:

最大化する式: $ (\log(x) + \sqrt{y}) $

制約条件:

  1. $ (x^2 + y^2 \leq 50) $
  2. $ (2x - y \geq 5) $
  3. $ (x \geq 1) $
  4. $ (y \geq 1) $

これをCVXPYを使って解き、その後結果をグラフで表現してみましょう。

解答例

下記のソースコードは解答例となります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

# 変数の定義
x = cp.Variable()
y = cp.Variable()

# 最大化する式の定義
objective = cp.Maximize(cp.log(x) + cp.sqrt(y))

# 制約条件の定義
constraints = [
x**2 + y**2 <= 50,
2*x - y >= 5,
x >= 1,
y >= 1
]

# 最適化問題の定義
problem = cp.Problem(objective, constraints)

# 問題を解く
problem.solve()

# 解を表示
print("Optimal value:", problem.value)
print("Optimal x:", x.value)
print("Optimal y:", y.value)

# グラフで可視化
theta = np.linspace(0, 2*np.pi, 100)
circle_x = np.sqrt(50) * np.cos(theta)
circle_y = np.sqrt(50) * np.sin(theta)

plt.figure(figsize=(8, 6))
plt.plot(circle_x, circle_y, label='Constraint 1: x^2 + y^2 <= 50')
plt.fill_between(circle_x, circle_y, color='gray', alpha=0.2)
plt.plot([1, 15], [2 * x.value - 5, 2 * x.value - 5], label='Constraint 2: 2x - y >= 5')
plt.ylim([0, 10])
plt.xlim([0, 10])
plt.scatter(x.value, y.value, color='red', label='Optimal Point')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.title('Optimization with Constraints')
plt.grid(True)
plt.show()

このコードを実行すると、最適な$ (x) $と$ (y) $の値が表示され、また制約条件を含んだグラフも描画されます。

[実行結果]

ソースコード解説

コードの各部分を詳しく見ていきましょう。

1
2
3
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

ここでは、必要なライブラリをインポートしています。

cvxpyは最適化問題を解くためのライブラリで、numpyは数値計算のためのライブラリ、matplotlib.pyplotはグラフ描画のためのライブラリです。

1
2
3
# 変数の定義
x = cp.Variable()
y = cp.Variable()

cp.Variable()を使って最適化問題の変数 xy を定義しています。

1
2
# 最大化する式の定義
objective = cp.Maximize(cp.log(x) + cp.sqrt(y))

cp.Maximize()を使って最大化したい式を定義しています。

この場合、$ (\log(x) + \sqrt{y}) $を最大化します。

1
2
3
4
5
6
7
# 制約条件の定義
constraints = [
x**2 + y**2 <= 50,
2*x - y >= 5,
x >= 1,
y >= 1
]

constraintsには、最適化問題の制約条件がリストとして定義されています。

ここでは、$ (x^2 + y^2 \leq 50) $、$ (2x - y \geq 5) $、$ (x \geq 1) $、$ (y \geq 1) $という制約条件が設定されています。

1
2
# 最適化問題の定義
problem = cp.Problem(objective, constraints)

cp.Problem()を使って最適化問題を定義しています。

この問題には、先ほど定義した目的関数制約条件が含まれています。

1
2
# 問題を解く
problem.solve()

problem.solve()を使って定義した最適化問題を解きます。

これにより、最適な解が計算されます。

1
2
3
4
# 解を表示
print("Optimal value:", problem.value)
print("Optimal x:", x.value)
print("Optimal y:", y.value)

ここでは、求められた最適な解の目的関数の値、および$ (x) $と$ (y) $の値を表示しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# グラフで可視化
theta = np.linspace(0, 2*np.pi, 100)
circle_x = np.sqrt(50) * np.cos(theta)
circle_y = np.sqrt(50) * np.sin(theta)

plt.figure(figsize=(8, 6))
plt.plot(circle_x, circle_y, label='Constraint 1: x^2 + y^2 <= 50')
plt.fill_between(circle_x, circle_y, color='gray', alpha=0.2)
plt.plot([1, 15], [2 * x.value - 5, 2 * x.value - 5], label='Constraint 2: 2x - y >= 5')
plt.ylim([0, 10])
plt.xlim([0, 10])
plt.scatter(x.value, y.value, color='red', label='Optimal Point')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.title('Optimization with Constraints')
plt.grid(True)
plt.show()

最後の部分では、解を可視化するためにmatplotlibを使ってグラフを作成しています。

plt.plot()を使って制約条件を表す円と直線をプロットし、plt.scatter()で最適解を赤い点として表示しています。

これにより、最適化問題の定式化から解の計算、そしてグラフでの視覚化までが行われます。

結果解説

最適な解は、目的関数の値が約3.85で、$ (x) $の値は約5.0、$ (y) $の値は約5.0です。

これは与えられた制約条件の下で最大化された目的関数の値とその$ (x) $、$ (y) $の値です。

グラフでは、以下の内容を示しています:

1. 円形の領域:

制約条件$ (x^2 + y^2 \leq 50) $を表しており、この領域内に解が存在することを示しています。

2. 直線:

制約条件$ (2x - y \geq 5) $を表しています。
最適解はこの直線の上側に位置しています。

3. 赤い点:

最適解が示されており、目的関数を最大化するための$ (x) $と$ (y) $の値です。

この結果から、与えられた非線形最適化問題において、目的関数を最大化する$ (x) $と$ (y) $の値が見つかりました。

制約条件を満たしつつ、最適な解を見つけることができました。

次元削減(主成分分析) scikit-learn

次元削減(主成分分析)

scikit-learnは機械学習ライブラリであり、貿易問題を直接解決するためのツールではありませんが、クラスタリングや次元削減などの手法を使用してデータを分析し、貿易パターンを視覚化することができます。

例として、異なる国の貿易データを考え、それをscikit-learnを用いて次元削減(主成分分析)し、結果を可視化してみます。

実際の貿易データを使用せず、ダミーデータを生成して使います。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

# ダミーデータ生成
# 3つの国、4つの商品(リンゴ、バナナ、オレンジ、グレープ)の貿易データを生成します
np.random.seed(42)
countries = ['Country A', 'Country B', 'Country C']
num_products = 4
num_samples = 100

# ダミーの貿易データ生成
data = np.random.randint(0, 100, size=(num_samples, num_products * len(countries)))

# 主成分分析 (PCA) を用いて次元削減
pca = PCA(n_components=2)
transformed_data = pca.fit_transform(data)

# 可視化
plt.figure(figsize=(8, 6))
for i, country in enumerate(countries):
indices = range(i * num_products, (i + 1) * num_products)
plt.scatter(transformed_data[:, 0][indices], transformed_data[:, 1][indices], label=country)

plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.title('Trade Data Visualization')
plt.legend()
plt.grid(True)
plt.show()

この例では、3つの国間で4つの商品の貿易データを生成し、PCAを使って次元を2つに削減します。

その後、2つの主成分をx軸とy軸として、それぞれの国のデータをプロットしています。

実際のデータを使用する場合、より意味のある視覚化が可能です。

ソースコード解説

ソースコードを詳しく見ていきましょう。

1. ライブラリのインポート

1
2
3
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
  • numpyは数値計算を行うためのライブラリです。
  • matplotlibはグラフ描画のためのライブラリで、pyplotモジュールをpltとしてインポートします。
  • sklearnPCAは、主成分分析を実行するためのクラスです。

2. ダミーデータの生成

1
2
3
4
5
np.random.seed(42)
countries = ['Country A', 'Country B', 'Country C']
num_products = 4
num_samples = 100
data = np.random.randint(0, 100, size=(num_samples, num_products * len(countries)))
  • np.random.seed(42)は乱数生成器のシードを設定し、乱数の再現性を確保します。
  • countriesは国のリストを表し、3つの国が含まれています。
  • num_productsは商品の数を示し、ここでは4つの商品があります。
  • num_samplesはサンプルの数を示します。ここでは各国の商品の貿易データを100サンプル生成します。
  • np.random.randint(0, 100, size=(num_samples, num_products * len(countries)))は、0から99の間のランダムな整数で、各国の各商品の貿易データを生成します。

3. 主成分分析 (PCA) を用いた次元削減

1
2
pca = PCA(n_components=2)
transformed_data = pca.fit_transform(data)
  • PCA(n_components=2)は、2次元に次元削減するPCAのインスタンスを作成します。
  • pca.fit_transform(data)は、生成された貿易データを使って主成分分析を行い、データを2次元に変換します。

4. 可視化

1
2
3
4
5
6
7
8
9
10
11
plt.figure(figsize=(8, 6))
for i, country in enumerate(countries):
indices = range(i * num_products, (i + 1) * num_products)
plt.scatter(transformed_data[:, 0][indices], transformed_data[:, 1][indices], label=country)

plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.title('Trade Data Visualization')
plt.legend()
plt.grid(True)
plt.show()
  • plt.figure(figsize=(8, 6))でグラフのサイズを設定します。
  • forループは各国の貿易データをプロットします。
  • plt.scatter()は散布図をプロットします。ここでは主成分1と主成分2をx軸とy軸にしてプロットしています。
  • plt.xlabel()plt.ylabel()でx軸とy軸のラベルを設定し、plt.title()でグラフのタイトルを設定します。
  • plt.legend()で凡例を表示し、plt.grid(True)でグリッド線を表示します。
  • plt.show()でグラフを表示します。

これにより、ダミーの貿易データをPCAで2次元に変換し、各国の商品の貿易パターンを可視化するグラフが作成されます。

結果解説

生成されたグラフは、3つの国(Country A、Country B、Country C)間で4つの商品(リンゴ、バナナ、オレンジ、グレープ)の貿易データの次元削減結果を可視化したものです。

横軸と縦軸はそれぞれ主成分分析(PCA)によって得られた2つの主成分です。
これらの主成分は元の多次元のデータをより少ない次元(ここでは2次元)に圧縮したものです。

それぞれの国は異なる色で表されており、各国の点の集まりがその国の商品の貿易パターンを示しています。
点が近くに集まっている場合、その国は類似した貿易パターンを持っていることを示しています。
逆に、点が離れている場合、その国の商品の貿易パターンは異なる可能性があります。

グラフ上の点が重なっている場合、その点のデータは次元削減によって同じ位置にマッピングされたため、視覚的には1つの点に見えますが、実際には複数のデータ点が含まれています。

このグラフは、異なる国の間での商品の貿易パターン類似性を視覚的に理解するのに役立ちます。
もし実際の貿易データがあれば、これらの点のパターンクラスタリングをより詳細に解釈することができます。

線形回帰モデル(燃費) scikit-learn

線形回帰モデル(燃費)

scikit-learnを使用して、線形回帰モデルを作成してみましょう。

以下は、燃費データを使って車の燃費を予測する例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import pandas as pd
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

# データの読み込み
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data"
column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight', 'Acceleration', 'Model Year', 'Origin']
data = pd.read_csv(url, sep='\s+', names=column_names, na_values='?')

# 欠損値を削除
data = data.dropna()

# 特徴量とターゲットの選択
X = data[['Cylinders', 'Displacement', 'Horsepower', 'Weight', 'Acceleration']]
y = data['MPG']

# モデルの訓練
model = LinearRegression()
model.fit(X, y)

# 予測と実際の値の比較
predictions = model.predict(X)

# グラフ化
plt.figure(figsize=(10, 6))
plt.scatter(y, predictions)
plt.xlabel('実際のMPG')
plt.ylabel('予測されたMPG')
plt.title('実際のMPGと予測されたMPGの比較')
plt.grid(True)
plt.show()

このコードでは、UCI Machine Learning Repositoryから車の燃費データを読み込み、線形回帰モデルを用いて車の燃費(MPG)を予測します。

そして、実際のMPGと予測されたMPGの比較を散布図として表示しています。

ソースコード解説

このコードは、以下の手順で車の燃費(MPG)データを分析し、線形回帰モデルを作成しています。

データの読み込みと前処理

  • UCI Machine Learning Repositoryから車の燃費データをダウンロードし、Pandasを使って読み込みます。
  • データにはカラム名がないので、カラム名を定義しています。
  • 欠損値が含まれる可能性があるため、欠損値を含む行を削除します。

特徴量とターゲットの選択

  • 説明変数(特徴量)目的変数(ターゲット)を選択します。
    ここでは、車の性能に関連する特徴量(気筒数、排気量、馬力、重量、加速度)を特徴量として選択し、燃費(MPG)を目的変数として選択しています。

モデルの訓練

  • scikit-learnのLinearRegression()を使用して線形回帰モデルを作成し、特徴量と目的変数を使ってモデルを訓練します。

予測と実際の値の比較

  • 訓練済みモデルを使って、特徴量から燃費(MPG)を予測します。
  • 実際の燃費と予測された燃費の関係を比較するため、散布図を作成しています。

グラフ化

  • 予測されたMPGと実際のMPGを散布図で表示しており、x軸が実際のMPG、y軸が予測されたMPGを示しています。
  • グラフのタイトルや軸ラベルが追加されており、グリッドが表示されています。

結果解説

このグラフは、実際の燃費(実際のMPG)と機械学習モデルによって予測された燃費(予測されたMPG)の関係を示しています。

各点は、個々の車両に対しての実際の燃費とモデルによる予測のペアを表しています。

x軸は実際のMPGを示し、y軸はそれに対する機械学習モデルによる予測されたMPGを表しています。

各点が45度の直線に近い位置に集中している場合、予測が実際の値とほぼ同じであることを意味します。

グラフ全体が45度の直線に近い形をしている場合、モデルが実際の値と良好に一致して予測していることを示し、点が直線から離れてばらつきが大きい場合、予測が実際の値との間で大きくズレていることを示します。

高度な数式 SciPy

高度な数式

Scipyを使用して、高度な数式を解くためのサンプルコードを提供します。

以下は、$ y = x^3 + 2x^2 - 5x + 6 $の関数を考え、その解を見つける例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import numpy as np
from scipy.optimize import root
import matplotlib.pyplot as plt

# 解きたい方程式の関数
def equation(x):
return x**3 + 2*x**2 - 5*x + 6

# 初期値を設定
initial_guess = 0

# 方程式の解を求める
solution = root(equation, initial_guess)

# 解を表示
print("解:", solution.x)

# グラフ化
x_vals = np.linspace(-5, 3, 1000)
y_vals = equation(x_vals)

plt.figure(figsize=(8, 6))
plt.plot(x_vals, y_vals, label='y = x^3 + 2x^2 - 5x + 6')
plt.scatter(solution.x, equation(solution.x), color='red', label='Solution', s=100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Graph of the Equation')
plt.legend()
plt.grid(True)
plt.show()

このコードは、scipy.optimize.rootを使用して方程式の解を見つけます。

また、解を求める過程をグラフに表しています。

方程式の解は赤い点で示されています。

ソースコード解説

このコードは、Scipyライブラリを使用して非線形方程式を解く手順を示しています。

詳細を以下にまとめます。

ライブラリのインポート

1
2
3
import numpy as np
from scipy.optimize import root
import matplotlib.pyplot as plt

方程式の定義

1
2
def equation(x):
return x**3 + 2*x**2 - 5*x + 6

この関数では、$ y = x^3 + 2x^2 - 5x + 6 $という非線形方程式が定義されています。

初期値の設定

1
initial_guess = 0

初期推定値を$ (x=0) $に設定しています。

方程式の解を求める

1
solution = root(equation, initial_guess)

scipy.optimize.rootを使用して、指定した方程式の解を計算します。
この場合、equation関数を与えています。

解の表示

1
print("解:", solution.x)

解をコンソールに表示します。

グラフ化

1
2
3
4
5
6
7
8
9
10
11
12
x_vals = np.linspace(-5, 3, 1000)
y_vals = equation(x_vals)

plt.figure(figsize=(8, 6))
plt.plot(x_vals, y_vals, label='y = x^3 + 2x^2 - 5x + 6')
plt.scatter(solution.x, equation(solution.x), color='red', label='Solution', s=100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('Graph of the Equation')
plt.legend()
plt.grid(True)
plt.show()

指定した範囲の$ (x) 値$に対する方程式の$ (y) 値$を計算し、グラフ上に方程式の曲線を描画します。

また、方程式の解を赤い点で示しています。

このコード全体は、非線形方程式の数値解法とその結果の視覚化を行っています。

統計 SciPy

統計

統計に関する問題をSciPyを使用して解いて、その結果をグラフ化します。

以下は、あるデータセットを使って簡単な統計的な問題を解決し、その結果をグラフ化する例です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt

# サンプルデータ生成
np.random.seed(0)
data = np.random.normal(loc=5, scale=2, size=1000) # 平均=5, 標準偏差=2の正規分布からのサンプルデータ

# データの基本的な統計量計算
mean = np.mean(data)
std_dev = np.std(data)
median = np.median(data)

# 正規分布の確率密度関数の作成
x = np.linspace(np.min(data), np.max(data), 100)
pdf = norm.pdf(x, mean, std_dev)

# グラフ化
plt.figure(figsize=(10, 6))

# ヒストグラム
plt.hist(data, bins=30, density=True, alpha=0.5, label='Histogram')

# 正規分布の確率密度関数
plt.plot(x, pdf, 'r', label='Normal Distribution')

# 平均と中央値の縦線
plt.axvline(mean, color='green', linestyle='dashed', linewidth=2, label='Mean')
plt.axvline(median, color='orange', linestyle='dashed', linewidth=2, label='Median')

plt.title('Histogram and Normal Distribution of Data')
plt.xlabel('Values')
plt.ylabel('Density')
plt.legend()
plt.grid(True)
plt.show()

# 統計量の表示
print(f"平均: {mean}")
print(f"標準偏差: {std_dev}")
print(f"中央値: {median}")

このコードは、平均・標準偏差・中央値の計算、データのヒストグラム正規分布の確率密度関数のグラフ表示を行います。

また、平均中央値を縦線で示しています。

これにより、データの分布や統計的な特性を視覚化し、計算結果を表示します。

ソースコード解説

以下にソースコードの詳細を説明します。

ライブラリのインポートとサンプルデータの生成

1
2
3
4
5
6
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt

np.random.seed(0)
data = np.random.normal(loc=5, scale=2, size=1000)
  • numpyは数値計算を行うためのライブラリです。
    scipy.statsからnormは正規分布を扱うための統計関数を提供します。
    matplotlib.pyplotはグラフ描画ライブラリです。
  • np.random.normal()は平均が5で標準偏差が2の正規分布から1000個のサンプルデータを生成します。

基本的な統計量の計算

1
2
3
mean = np.mean(data)
std_dev = np.std(data)
median = np.median(data)
  • np.mean()np.std()np.median()はそれぞれデータの平均、標準偏差、中央値を計算します。

正規分布の確率密度関数の作成

1
2
x = np.linspace(np.min(data), np.max(data), 100)
pdf = norm.pdf(x, mean, std_dev)
  • np.linspace()dataの最小値から最大値までの範囲を100個の等間隔な数値に分割します。
    これにより、x軸の値を作成します。
  • norm.pdf()は平均と標準偏差を指定して、正規分布の確率密度関数を計算します。

グラフ化

1
2
3
4
5
6
7
8
9
10
11
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, density=True, alpha=0.5, label='Histogram')
plt.plot(x, pdf, 'r', label='Normal Distribution')
plt.axvline(mean, color='green', linestyle='dashed', linewidth=2, label='Mean')
plt.axvline(median, color='orange', linestyle='dashed', linewidth=2, label='Median')
plt.title('Histogram and Normal Distribution of Data')
plt.xlabel('Values')
plt.ylabel('Density')
plt.legend()
plt.grid(True)
plt.show()
  • plt.figure(figsize=(10, 6))は図のサイズを設定します。
  • plt.hist()はヒストグラムを描画します。
  • plt.plot()は正規分布の確率密度関数を描画します。
  • plt.axvline()は平均と中央値を縦線で表示します。それぞれ緑とオレンジの破線で示されています。
  • plt.title()plt.xlabel()plt.ylabel()はそれぞれグラフのタイトルと軸ラベルを設定します。
  • plt.legend()は凡例を表示し、plt.grid(True)はグリッドを表示します。
  • plt.show()はグラフを表示します。

統計量の表示

1
2
3
print(f"平均: {mean}")
print(f"標準偏差: {std_dev}")
print(f"中央値: {median}")
  • 最後に、計算された平均、標準偏差、中央値を表示します。

ポートフォリオ最適化(凸最適化) CVXPY

ポートフォリオ最適化(凸最適化)

CVXPY凸最適化のためのライブラリです。

以下では、例としてポートフォリオ最適化問題を解いてみましょう。

ポートフォリオ最適化は投資資産の配分を決定する問題で、リスクを最小化しつつ期待収益を最大化する配分を見つけます。

まず、例として適当なデータを生成し、それを用いてポートフォリオ最適化を行います。

その後、結果をグラフ化します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt

# データ生成
np.random.seed(42)
n = 5 # 資産の数
mean_returns = np.random.randn(n) / 100 # 平均収益率
cov_matrix = np.random.randn(n, n)
cov_matrix = np.dot(cov_matrix.T, cov_matrix) / 100 # 共分散行列

# ポートフォリオ最適化問題の定義
weights = cp.Variable(n)
expected_return = mean_returns.T @ weights
risk = cp.quad_form(weights, cov_matrix)
constraints = [
cp.sum(weights) == 1, # 資産の割合の合計は1
weights >= 0 # 資産の割合は0以上
]
problem = cp.Problem(cp.Maximize(expected_return - 0.5 * risk), constraints) # 目的関数

# 最適化
result = problem.solve()

# 結果を表示
print("最適化されたポートフォリオの割合:")
print(weights.value)
print("期待収益率:", expected_return.value)
print("リスク:", np.sqrt(risk.value))

# グラフ化
plt.figure(figsize=(8, 6))
plt.bar(range(n), weights.value, tick_label=[f"Asset {i+1}" for i in range(n)])
plt.xlabel('Assets')
plt.ylabel('Portfolio Weights')
plt.title('Optimized Portfolio Allocation')
plt.show()

このコードは、CVXPYを使ってランダムな収益率共分散行列を生成し、ポートフォリオの最適な資産割合を求めます。

そして、最適化されたポートフォリオの割合を棒グラフで表示します。

[実行結果]

ソースコード解説

以下にソースコードの詳細を示します。

1. ライブラリのインポート

1
2
3
import cvxpy as cp
import numpy as np
import matplotlib.pyplot as plt
  • cvxpyは凸最適化問題を解くためのライブラリです。
  • numpyは数値計算を行うためのライブラリです。
  • matplotlib.pyplotはグラフを描画するためのライブラリです。

2. データの生成

1
2
3
4
5
np.random.seed(42)
n = 5 # 資産の数
mean_returns = np.random.randn(n) / 100 # 平均収益率
cov_matrix = np.random.randn(n, n)
cov_matrix = np.dot(cov_matrix.T, cov_matrix) / 100 # 共分散行列
  • mean_returnsは資産の平均収益率をランダムに生成しています。
  • cov_matrixは共分散行列を生成しています。
    この行列は資産間の関係性(共分散)を表します。

3. ポートフォリオ最適化問題の定義

1
2
3
4
5
6
7
8
weights = cp.Variable(n)
expected_return = mean_returns.T @ weights
risk = cp.quad_form(weights, cov_matrix)
constraints = [
cp.sum(weights) == 1, # 資産の割合の合計は1
weights >= 0 # 資産の割合は0以上
]
problem = cp.Problem(cp.Maximize(expected_return - 0.5 * risk), constraints) # 目的関数
  • weightsは資産の割合を表す変数です。
  • expected_returnはポートフォリオの期待収益率を表します。
  • riskはポートフォリオのリスクを表します。
  • constraintsでは資産の割合が0以上で合計が1であることを制約として設定しています。
  • problemは最大化する目的関数を定義しています。

4. 最適化

1
result = problem.solve()
  • problem.solve()でポートフォリオ最適化問題を解きます。

5. 結果の表示

1
2
3
4
print("最適化されたポートフォリオの割合:")
print(weights.value)
print("期待収益率:", expected_return.value)
print("リスク:", np.sqrt(risk.value))
  • 最適化されたポートフォリオの割合、期待収益率、リスクを表示しています。

6. グラフ化

1
2
3
4
5
6
plt.figure(figsize=(8, 6))
plt.bar(range(n), weights.value, tick_label=[f"Asset {i+1}" for i in range(n)])
plt.xlabel('Assets')
plt.ylabel('Portfolio Weights')
plt.title('Optimized Portfolio Allocation')
plt.show()
  • 最適化されたポートフォリオの割合を棒グラフで表示しています。
    各資産の割合を視覚的に確認できます。

結果解説

[実行結果]

この結果は、ポートフォリオの最適化後の割合期待収益率、そしてリスクを示しています。

最適化されたポートフォリオの割合:

各資産の最適な配分を示しています。
例えば、1番目の資産の割合は約12.20%、3番目の資産の割合は約60.58%、4番目の資産の割合は約27.22%となっています。
2番目と最後の資産はほとんど割り当てられていません。

期待収益率:

最適化されたポートフォリオの期待収益率は約0.0087です。
これは、ポートフォリオが1単位投資した場合の平均的なリターンを示しています。

リスク:

ポートフォリオのリスクは、標準偏差またはボラティリティを示しており、約0.0575です。
この値はポートフォリオの変動性を表しています。