カスタムクロスオーバーと突然変異 DEAP

DEAP

DEAP(Distributed Evolutionary Algorithms in Python)は、遺伝的アルゴリズム(GA)進化戦略(ES)などの進化的計算手法を実装するための強力で柔軟なライブラリです。

以下に、DEAPの高度な使い方を紹介します。

カスタムクロスオーバーと突然変異

DEAPでは独自のクロスオーバー突然変異オペレーターを定義して、遺伝的アルゴリズムの動作をカスタマイズできます。

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import random
import multiprocessing
from deap import base, creator, tools, algorithms

# 適応度と個体の定義
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

# 個体生成関数
def create_individual():
return [random.uniform(-10, 10) for _ in range(3)]

# 適応度関数
def evaluate(individual):
return sum(ind ** 2 for ind in individual),

# カスタムクロスオーバー
def custom_crossover(ind1, ind2):
size = len(ind1)
cxpoint = random.randint(1, size - 1)
ind1[cxpoint:], ind2[cxpoint:] = ind2[cxpoint:], ind1[cxpoint:]
return ind1, ind2

# カスタム突然変異
def custom_mutation(individual, indpb):
for i in range(len(individual)):
if random.random() < indpb:
individual[i] = random.uniform(-10, 10)
return individual,

# 登録
toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", custom_crossover)
toolbox.register("mutate", custom_mutation, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)

# 並列化の設定
pool = multiprocessing.Pool()
toolbox.register("map", pool.map)

# メイン実行ループ
population = toolbox.population(n=300)
NGEN = 40
for gen in range(NGEN):
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))

for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.5:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values

for mutant in offspring:
if random.random() < 0.2:
toolbox.mutate(mutant)
del mutant.fitness.values

invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit

population[:] = offspring

pool.close()
pool.join()

best_ind = tools.selBest(population, 1)[0]
print(f"Best individual is {best_ind}, {best_ind.fitness.values}")

[実行結果]

Best individual is [-9.982904889626795, 9.853294237890143, -9.986879615364009], (296.4835618255468,)

ソースコード解説

このソースコードは、$DEAP(Distributed Evolutionary Algorithms in Python)$ライブラリを使用して、遺伝的アルゴリズムを実行するプログラムです。

遺伝的アルゴリズムは、生物の進化のプロセスに基づいた最適化手法です。

コードを説明します。

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

1
2
3
import random
import multiprocessing
from deap import base, creator, tools, algorithms

DEAPランダム生成並列処理を行うためのライブラリをインポートします。

2. 適応度と個体の定義

1
2
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)
  • FitnessMax: 適応度クラスを作成し、最大化問題を定義します(weights=(1.0,)は最大化を意味します)。
  • Individual: 個体クラスを作成し、リストとして表現される個体にFitnessMax適応度を持たせます。

3. 個体生成関数

1
2
def create_individual():
return [random.uniform(-10, 10) for _ in range(3)]

個体を生成する関数。
3つの要素を持つリストを返し、各要素は$-10$から$10$の範囲でランダムに生成されます。

4. 適応度関数

1
2
def evaluate(individual):
return sum(ind ** 2 for ind in individual),

個体の適応度を計算する関数。
各要素の二乗の和を計算して返します。

5. カスタムクロスオーバー

1
2
3
4
5
def custom_crossover(ind1, ind2):
size = len(ind1)
cxpoint = random.randint(1, size - 1)
ind1[cxpoint:], ind2[cxpoint:] = ind2[cxpoint:], ind1[cxpoint:]
return ind1, ind2

カスタムクロスオーバー関数。
2つの親個体を交差点で交換します。

6. カスタム突然変異

1
2
3
4
5
def custom_mutation(individual, indpb):
for i in range(len(individual)):
if random.random() < indpb:
individual[i] = random.uniform(-10, 10)
return individual,

カスタム突然変異関数。
個体の各要素を一定の確率(indpb)でランダムに変更します。

7. 登録

1
2
3
4
5
6
7
toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", custom_crossover)
toolbox.register("mutate", custom_mutation, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)
  • toolboxに各種操作を登録します。
    • 個体生成、個体群生成、交叉、突然変異、選択、評価関数を登録します。

8. 並列化の設定

1
2
pool = multiprocessing.Pool()
toolbox.register("map", pool.map)

並列処理のためのプールを作成し、toolboxのmap関数をプールのmap関数に登録します。

9. メイン実行ループ

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
population = toolbox.population(n=300)
NGEN = 40
for gen in range(NGEN):
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))

for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.5:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values

for mutant in offspring:
if random.random() < 0.2:
toolbox.mutate(mutant)
del mutant.fitness.values

invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit

population[:] = offspring

pool.close()
pool.join()
  • 初期個体群($300$個体)を生成し、$40$世代にわたって進化させます。
  • 各世代で選択交叉突然変異を行い、新しい個体群を生成します。
  • 不正な適応度を持つ個体を評価し、適応度を更新します。

10. 最良の個体の表示

1
2
best_ind = tools.selBest(population, 1)[0]
print(f"Best individual is {best_ind}, {best_ind.fitness.values}")

最良の個体を選択し、その個体と適応度を表示します。

このコードは、遺伝的アルゴリズムを使用して3次元ベクトルの最適化を行うプログラムです。

各世代で選択交叉突然変異を行い、最適な個体を見つけるために進化を繰り返します。

最終的に、最も適応度の高い個体が表示されます。

結果解説

表示された結果について、説明します。

出力結果

1
Best individual is [-9.982904889626795, 9.853294237890143, -9.986879615364009], (296.4835618255468,)

各要素の解説

  1. Best individual:

    • [-9.982904889626795, 9.853294237890143, -9.986879615364009]:
      • これは遺伝的アルゴリズムの最適化プロセスを通じて見つかった最良の個体(解)です。
        この個体は3つの要素(遺伝子)を持つリストで、それぞれが探索空間内の数値です。
  2. Fitness value:

    • (296.4835618255468,):
      • これは最良の個体の適応度(評価値)です。
        適応度は、evaluate関数を通じて計算された値です。
        この関数では、個体の各要素の二乗の和を計算しています。
      • 適応度が高いほど(この場合は値が大きいほど)、個体の性能が良いことを示しています。

コードの動作の解説

以下に、コードがどのようにしてこの結果に到達したかを説明します。

  1. 初期化:

    • 適応度と個体のクラスを定義し、初期個体を生成します。
      各個体はランダムに生成された3つの浮動小数点数を含んでいます。
  2. 評価:

    • evaluate関数は、個体の各要素の二乗の和を計算し、その結果を適応度として返します。
  3. カスタムクロスオーバーと突然変異:

    • カスタムクロスオーバーは、二つの個体を交叉点で交叉させることによって新しい個体を生成します。
    • カスタム突然変異は、個体の各要素を一定の確率でランダムに新しい値に変えます。
  4. 進化のメインループ:

    • 各世代で、選択、交叉、突然変異を繰り返し行い、次世代の個体群を生成します。
    • 各世代の終わりに、適応度が評価され、次の世代の個体群が更新されます。
  5. 最良の個体の選択:

    • 最後に、全ての世代を通じて最も高い適応度を持つ個体(最良の個体)が選ばれ、その個体と適応度が表示されます。

結論

  • この出力は、与えられた目的関数に対して、遺伝的アルゴリズムが見つけた最良の解を示しています。
    個体の各要素は、探索空間内の数値であり、適応度はその個体の性能を評価した値です。

パラレル化 DEAP

DEAP

DEAP(Distributed Evolutionary Algorithms in Python)は、遺伝的アルゴリズム(GA)進化戦略(ES)などの進化的計算手法を実装するための強力で柔軟なライブラリです。

以下に、DEAPの高度な使い方を紹介します。

パラレル化

DEAP並列処理を簡単にサポートしており、大規模な問題を効率的に解くことができます。

multiprocessingモジュールを使用して、評価関数の並列化を行います。

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
49
50
51
52
53
54
55
56
57
58
59
import random
import multiprocessing
from deap import base, creator, tools, algorithms

# 適応度と個体の定義
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

# 個体生成関数
def create_individual():
return [random.uniform(-10, 10) for _ in range(3)]

# 適応度関数
def evaluate(individual):
return sum(ind ** 2 for ind in individual),

# 登録
toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)

# 並列化の設定
pool = multiprocessing.Pool()
toolbox.register("map", pool.map)

# メイン実行ループ
population = toolbox.population(n=300)
NGEN = 40
for gen in range(NGEN):
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))

for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.5:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values

for mutant in offspring:
if random.random() < 0.2:
toolbox.mutate(mutant)
del mutant.fitness.values

invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit

population[:] = offspring

pool.close()
pool.join()

best_ind = tools.selBest(population, 1)[0]
print(f"Best individual is {best_ind}, {best_ind.fitness.values}")

[実行結果]

Best individual is [917758.6757183365, -36.45732263984088, -2555.157039370527], (842287517012.9069,)

ソースコード解説

このコードは、遺伝的アルゴリズム(GA)を用いて問題を解くためのものであり、DEAPライブラリを使用して実装されています。

以下に、コードを章立てて詳しく説明します。

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

1
2
3
import random
import multiprocessing
from deap import base, creator, tools, algorithms

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

  • random: ランダムな数値生成に使用。
  • multiprocessing: 並列処理を行うためのライブラリ。
  • deap: 遺伝的アルゴリズムを実装するためのライブラリ。

2. 適応度と個体の定義

1
2
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

ここでは、DEAPのcreatorモジュールを使って適応度と個体のクラスを定義しています。

  • FitnessMax: 適応度を最大化するためのクラス。
  • Individual: 個体を表すクラス。
    このクラスはリストとして表現され、FitnessMaxを適応度として持つ。

3. 個体生成関数

1
2
def create_individual():
return [random.uniform(-10, 10) for _ in range(3)]

この関数は、ランダムな$3$つの実数からなる個体を生成します。
各要素は$-10$から$10$の間でランダムに選ばれます。

4. 適応度関数

1
2
def evaluate(individual):
return sum(ind ** 2 for ind in individual),

この関数は、個体の適応度を評価します。

ここでは、各要素の$2$乗の合計を返します。

5. DEAPのツールボックスに関数を登録

1
2
3
4
5
6
7
toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)

ここでは、GAで使用する操作をtoolboxに登録しています。

  • individual: 個体を生成する。
  • population: 集団(個体のリスト)を生成する。
  • mate: 交叉操作。
  • mutate: 変異操作。
  • select: 選択操作。
  • evaluate: 適応度を評価する。

6. 並列化の設定

1
2
pool = multiprocessing.Pool()
toolbox.register("map", pool.map)

ここでは、並列処理を行うための設定を行います。

pool.maptoolboxに登録することで、評価関数の並列化が可能になります。

7. メイン実行ループ

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
population = toolbox.population(n=300)
NGEN = 40
for gen in range(NGEN):
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))

for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.5:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values

for mutant in offspring:
if random.random() < 0.2:
toolbox.mutate(mutant)
del mutant.fitness.values

invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit

population[:] = offspring

pool.close()
pool.join()

このループでは、$40$世代にわたってGAを実行します。

  • population = toolbox.population(n=300): 初期集団を生成($300$個体)。
  • NGEN = 40: 世代数を設定。
  • 各世代で以下の操作を行います:
    1. 選択: toolbox.selectで選択された個体をoffspringに保存。
    2. 交叉: ランダムに選ばれたペアに対してtoolbox.mateを適用。
    3. 変異: ランダムに選ばれた個体に対してtoolbox.mutateを適用。
    4. 適応度の再評価: 適応度が無効になった個体の適応度を再評価。
    5. 集団の更新: 新しい世代に更新。

8. 最良の個体の選択と表示

1
2
best_ind = tools.selBest(population, 1)[0]
print(f"Best individual is {best_ind}, {best_ind.fitness.values}")

最良の個体を選択し、その個体と適応度を表示します。

まとめ

このコードは、DEAPライブラリと並列処理を用いて遺伝的アルゴリズムを実装しています。

GAを使用して、与えられた適応度関数に基づいて最適解を見つけるプロセスが示されています。

並列処理を用いることで、評価関数の計算を効率化しています。

結果解説

[実行結果]

Best individual is [917758.6757183365, -36.45732263984088, -2555.157039370527], (842287517012.9069,)

この結果は、遺伝的アルゴリズム(GA)を用いて最適化された個体(解)が示されています。

ここでは、その個体とその適応度(評価値)を詳しく解説します。

結果の詳細

  • Best individual: [917758.6757183365, -36.45732263984088, -2555.157039370527]

    • この配列は、GAによって最適化された3つの実数値からなるベクトルです。
      このベクトルが最も適した解(個体)として選ばれました。
    • 各要素は遺伝子を表し、GAの探索空間内で最適な解に収束するために変異や交叉によって進化しました。
  • 適応度 (Fitness): (842287517012.9069,)

    • 適応度は、個体の評価値を示します。
      遺伝的アルゴリズムの目的は、この適応度を最大化する(または最小化する)ことです。
    • 今回の評価関数は、個体の各遺伝子の2乗和を計算しています。
      そのため、評価値はベクトルの各要素の2乗和に等しくなります。

解説

  1. 個体の構成:

    • GAでは個体(解)は通常、固定長のベクトルとして表されます。
      このベクトルは問題の次元数(ここでは3次元)と同じ長さです。
    • 個体 [917758.6757183365, -36.45732263984088, -2555.157039370527] は3つの要素を持ちます。
  2. 適応度の計算:

    • 適応度関数 evaluate(individual) は、与えられた個体の各要素の2乗の合計を計算します。
      具体的には、次のようになります:
      $$
      \text{適応度} = 917758.6757183365^2 + (-36.45732263984088)^2 + (-2555.157039370527)^2
      $$
    • 実際の計算結果:
      $$
      917758.6757183365^2 \approx 842285214642.541
      $$
      $$
      (-36.45732263984088)^2 \approx 1329.247
      $$
      $$
      (-2555.157039370527)^2 \approx 652407.118
      $$
      これらを合計すると:
      $$
      842285214642.541 + 1329.247 + 652407.118 \approx 842287517012.9069
      $$
  3. 結果の意味:

    • この結果は、GAによって見つけられた最適な個体の一例です。
      個体の評価関数が2乗和であるため、この個体は探索空間内で最小の2乗和を持つものとなります。
    • 遺伝的アルゴリズムは、進化過程を通じて個体を選択、交叉、変異させながら適応度を最大化(または最小化)します。
  4. 適応度の高い個体の特徴:

    • 適応度が高い個体は、与えられた問題に対して優れた解を提供します。
      この場合、評価関数最小化問題であるため、適応度が小さいほど良い解とみなされます。

まとめ

このGAの実行結果は、3次元ベクトルで表される問題空間での最適解(または近似最適解)を示しています。

適応度はその個体の品質を示し、最小化された評価値が提示されています。

カスタム適応度関数 DEAP

DEAP

DEAP(Distributed Evolutionary Algorithms in Python)は、遺伝的アルゴリズム(GA)進化戦略(ES)などの進化的計算手法を実装するための強力で柔軟なライブラリです。

以下に、DEAPの高度な使い方を紹介します。

カスタム適応度関数

DEAPではカスタム適応度関数を定義して、特定の問題に対する適応度を評価できます。

ここでは、シンプルな最適化問題を例に説明します。

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
49
50
51
import random
from deap import base, creator, tools, algorithms

# 適応度と個体の定義
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

# 個体生成関数
def create_individual():
return [random.uniform(-10, 10) for _ in range(3)]

# 適応度関数
def evaluate(individual):
return sum(ind ** 2 for ind in individual),

# 登録
toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)

# メイン実行ループ
population = toolbox.population(n=300)
NGEN = 40
for gen in range(NGEN):
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))

for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.5:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values

for mutant in offspring:
if random.random() < 0.2:
toolbox.mutate(mutant)
del mutant.fitness.values

invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit

population[:] = offspring

best_ind = tools.selBest(population, 1)[0]
print(f"Best individual is {best_ind}, {best_ind.fitness.values}")

[実行結果]

Best individual is [17379.0603611039, 1705192.5401431422, 2.8390485621127146], (2907983630706.9165,)

ソースコード解説

このコードは、DEAPライブラリを使用して遺伝的アルゴリズムを実装しています。

以下に、詳しく説明します。

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

1
2
import random
from deap import base, creator, tools, algorithms

ここでは、Pythonの標準ライブラリであるrandomと、DEAPライブラリの主要なモジュール(base, creator, tools, algorithms)をインポートしています。
これにより、遺伝的アルゴリズムの構成要素を使用できるようになります。

2. 適応度と個体の定義

1
2
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

このセクションでは、DEAPcreatorモジュールを使用して、遺伝的アルゴリズムの基本的な構成要素である適応度と個体を定義します。

  • FitnessMax: 最大化問題の適応度クラスを定義します。
    weights=(1.0,) は、適応度を最大化することを示しています。
  • Individual: 遺伝的アルゴリズムで操作する個体を定義します。
    個体はリストで表され、その適応度はFitnessMaxです。

3. 個体生成関数

1
2
def create_individual():
return [random.uniform(-10, 10) for _ in range(3)]

この関数は、新しい個体を生成するための関数です。
ここでは、各個体は3つの遺伝子(ランダムな浮動小数点数)を持ちます。
各遺伝子の値は$-10$から$10$の範囲でランダムに生成されます。

4. 適応度関数

1
2
def evaluate(individual):
return sum(ind ** 2 for ind in individual),

適応度関数は、各個体の適応度を評価するための関数です。
この関数は、個体の各遺伝子の二乗和を計算し、その値を返します。
適応度の高い個体は、より良い解を表します。

5. 登録

1
2
3
4
5
6
7
toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)

ここでは、DEAPToolboxを使用して、遺伝的アルゴリズムのさまざまな操作を登録しています。

  • individual: 個体生成関数を登録します。
  • population: 個体の集団(ポピュレーション)生成関数を登録します。
  • mate: 交叉オペレーターを登録します。
    ここではブレンド交叉(cxBlend)を使用しています。
  • mutate: 突然変異オペレーターを登録します。
    ここではガウス分布に従う突然変異(mutGaussian)を使用しています。
  • select: 選択オペレーターを登録します。
    ここではトーナメント選択(selTournament)を使用しています。
  • evaluate: 適応度関数を登録します。

6. メイン実行ループ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
population = toolbox.population(n=300)
NGEN = 40
for gen in range(NGEN):
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))

for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.5:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values

for mutant in offspring:
if random.random() < 0.2:
toolbox.mutate(mutant)
del mutant.fitness.values

invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit

population[:] = offspring

このセクションでは、遺伝的アルゴリズムのメインループを実行しています。

  1. 初期集団の生成: toolbox.population(n=300) で300個体の初期集団を生成します。
  2. 世代ループ: 40世代(NGEN = 40)のループを実行します。
    • 選択: トーナメント選択を使用して、次世代の親を選択します。
    • 複製: 選択された親を複製して子供を作ります。
    • 交叉: 子供に対して交叉操作を行います。
      50%の確率で交叉します。
    • 突然変異: 子供に対して突然変異操作を行います。
      20%の確率で突然変異します。
    • 適応度の再評価: 交叉や突然変異で適応度が無効になった個体の適応度を再評価します。
    • 集団の更新: 新しい子供集団で現在の集団を置き換えます。

7. 最良個体の表示

1
2
best_ind = tools.selBest(population, 1)[0]
print(f"Best individual is {best_ind}, {best_ind.fitness.values}")

最後に、最良個体を選択し、その個体と適応度を表示します。

  • 最良個体の選択: tools.selBest を使用して、集団の中から最良の個体を選択します。
  • 結果の表示: 最良個体の遺伝子と適応度を表示します。

まとめ

このコードは、DEAPライブラリを使用して遺伝的アルゴリズムを実装する一連のステップを示しています。

具体的には、個体と適応度の定義、個体生成、適応度評価、遺伝的操作(交叉、突然変異、選択)、および最良個体の選択を含みます。

各ステップは、遺伝的アルゴリズムの効率的な実行を支援します。

結果解説

[実行結果]

Best individual is [17379.0603611039, 1705192.5401431422, 2.8390485621127146], (2907983630706.9165,)

この結果は、DEAPを使った遺伝的アルゴリズムの実行の最終結果です。

以下に各部分の詳細な解説を行います。

解説

  1. Best individual is [17379.0603611039, 1705192.5401431422, 2.8390485621127146]

    • Best individual: これは最適化の過程で見つかった最良の個体を示しています。
      個体はリストとして表示され、各要素は個体の遺伝子を表しています。
      ここでは、個体は3つの遺伝子 [17379.0603611039, 1705192.5401431422, 2.8390485621127146] を持っています。
    • 17379.0603611039, 1705192.5401431422, 2.8390485621127146: これらの値は、それぞれの遺伝子の値です。
      これらの遺伝子の組み合わせが、この特定の最適化問題において最良の解を提供したことを示しています。
  2. (2907983630706.9165,)

    • (2907983630706.9165,): これは最良の個体の適応度(fitness)を示しています。
      適応度は個体の「良さ」を表し、通常は評価関数によって計算されます。
      ここでは、適応度が 2907983630706.9165 であることを示しています。
      この値は、評価関数の定義によって大きく変わる可能性があります。

まとめ

この結果から、遺伝的アルゴリズムが非常に大きな値を持つ遺伝子を持つ個体を最適解として見つけたことがわかります。

適応度値評価関数に依存しており、この場合は遺伝子の値の二乗和として計算されています。

結果として表示される適応度は、その個体が他の個体と比べてどれだけ優れているかを示す指標です。

改善のためのヒント

  • 適応度関数の調整: もしこの適応度値が現実的でない場合や、解が望ましい範囲外にある場合は、適応度関数を見直すことを検討してください。
  • パラメータのスケーリング: 遺伝子値の範囲を制限したり、スケーリングを行うことで、最適化の精度を向上させることができます。
  • 他のオペレーターの利用: 異なる交叉や突然変異オペレーターを試すことで、進化の多様性を増やし、より良い解を見つける可能性があります。

DEAPは非常に柔軟なライブラリであり、様々なカスタマイズを行うことで多種多様な最適化問題に対応できます。

Seaborn

Seaborn

SeabornMatplotlibを基盤とした高レベルのデータ可視化ライブラリで、美しく統計的なプロットを簡単に作成することができます。

以下にSeabornの便利な使い方をいくつか紹介します。

基本的なプロット

1. インポートとデータセットの準備

1
2
3
4
5
import seaborn as sns
import matplotlib.pyplot as plt

# サンプルデータセットのロード
tips = sns.load_dataset("tips")

2. 散布図 (Scatter Plot)

1
2
sns.scatterplot(x="total_bill", y="tip", data=tips)
plt.show()

[実行結果]

3. 線形回帰プロット (Regression Plot)

1
2
sns.lmplot(x="total_bill", y="tip", data=tips)
plt.show()

[実行結果]

カテゴリカルデータのプロット

4. 棒グラフ (Bar Plot)

1
2
sns.barplot(x="day", y="total_bill", data=tips)
plt.show()

[実行結果]

5. 箱ひげ図 (Box Plot)

1
2
sns.boxplot(x="day", y="total_bill", data=tips)
plt.show()

[実行結果]

6. バイオリンプロット (Violin Plot)

1
2
sns.violinplot(x="day", y="total_bill", data=tips)
plt.show()

[実行結果]

分布の可視化

7. ヒストグラム (Histogram)

1
2
sns.histplot(tips["total_bill"], bins=20, kde=True)
plt.show()

[実行結果]

8. カーネル密度推定 (KDE Plot)

1
2
sns.kdeplot(tips["total_bill"], shade=True)
plt.show()

[実行結果]

マトリックスプロット

9. 相関行列 (Heatmap)

1
2
3
4
5
6
7
8
9
# 数値データのみを抽出
numeric_tips = tips.select_dtypes(include=['float64', 'int64'])

# 相関行列の計算
corr = numeric_tips.corr()

# ヒートマップのプロット
sns.heatmap(corr, annot=True, cmap="coolwarm")
plt.show()

[実行結果]

10. ペアプロット (Pair Plot)

1
2
sns.pairplot(tips)
plt.show()

[実行結果]

高度なプロット

11. Facet Grid

複数のプロットをグリッド形式で表示することができます。

1
2
3
g = sns.FacetGrid(tips, col="sex", hue="smoker")
g.map(sns.scatterplot, "total_bill", "tip").add_legend()
plt.show()

[実行結果]

12. カスタマイズ

SeabornのプロットはMatplotlibのプロットオブジェクトとして返されるため、Matplotlibの関数でさらにカスタマイズできます。

1
2
3
4
5
ax = sns.barplot(x="day", y="total_bill", data=tips)
ax.set_title("Total Bill per Day")
ax.set_xlabel("Day of the Week")
ax.set_ylabel("Total Bill")
plt.show()

[実行結果]

スタイルの設定

Seabornはスタイルの設定が容易です。

以下のコードでデフォルトスタイルを変更できます。

1
2
3
sns.set_style("whitegrid")
sns.scatterplot(x="total_bill", y="tip", data=tips)
plt.show()

[実行結果]

他のスタイルにはdarkgridwhitedarkticksがあります。

一般的な設定

一度に複数の設定を行うこともできます。

1
2
3
4
5
6
sns.set_context("talk")
sns.set_palette("muted")
sns.set_style("whitegrid")

sns.violinplot(x="day", y="total_bill", data=tips)
plt.show()

[実行結果]


これらの機能を使うことで、Seabornを用いて美しいデータビジュアライゼーションを簡単に作成することができます。

興味のあるプロットタイプデータセットに応じて、Seabornの多様な機能を試してみてください。

SciPyの高度な使い方

SciPyの高度な使い方

SciPyには高度な機能が豊富にあり、専門的な分析や計算を行うためのツールが多く提供されています。

以下に、SciPyの高度な使い方のいくつかを紹介します。

1. 高度な最適化

SciPyoptimize モジュールを使用して、制約付き最適化多目的最適化を実行できます。

制約付き最適化

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
from scipy.optimize import minimize

# 目的関数を定義
def objective(x):
return x[0]**2 + x[1]**2

# 制約を定義
def constraint1(x):
return x[0] - 2 * x[1] + 2

def constraint2(x):
return -x[0] - 2 * x[1] + 6

# 制約条件を辞書形式で指定
con1 = {'type': 'ineq', 'fun': constraint1}
con2 = {'type': 'ineq', 'fun': constraint2}
cons = [con1, con2]

# 初期値
x0 = [0.5, 0]

# 最適化
solution = minimize(objective, x0, method='SLSQP', constraints=cons)

print("最適化結果:", solution.x)

[実行結果]

最適化結果: [ 0.00000000e+00 -7.45058049e-09]

2. 非線形方程式の解法

SciPyoptimize モジュールを使用して非線形方程式を解くことができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from scipy.optimize import fsolve

# 方程式を定義
def equations(vars):
x, y = vars
eq1 = x**2 + y**2 - 4
eq2 = x * y - 1
return [eq1, eq2]

# 初期値
initial_guess = [1, 1]

# 方程式を解く
solution = fsolve(equations, initial_guess)

print("解:", solution)

[実行結果]

解: [1.93185165 0.51763809]

3. マルチプロセッシングによる並列計算

SciPyintegrate モジュールを使用して、複数の積分並列で計算できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from scipy import integrate
import numpy as np
from multiprocessing import Pool

# 積分する関数を定義
def f(x):
return np.sin(x)

# 積分範囲のリスト
ranges = [(0, np.pi/2), (0, np.pi), (0, 2*np.pi)]

# 並列計算のためのラッパー関数
def integrate_range(r):
return integrate.quad(f, r[0], r[1])[0]

# プロセスプールを作成
with Pool(processes=3) as pool:
results = pool.map(integrate_range, ranges)

print("積分結果:", results)

[実行結果]

積分結果: [0.9999999999999999, 2.0, 2.221501482512777e-16]

4. 高度な線形代数

SciPylinalg モジュールを使用して、疎行列の計算や行列分解を行うことができます。

疎行列の操作

1
2
3
4
5
6
7
8
9
10
11
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import spsolve

# 疎行列を作成
A = csr_matrix([[3, 1], [1, 2]])
b = np.array([9, 8])

# 疎行列を使って線形方程式を解く
x = spsolve(A, b)

print("解:", x)

[実行結果]

解: [2. 3.]

特異値分解

1
2
3
4
5
6
7
8
9
10
11
12
from scipy.linalg import svd
import numpy as np

# 行列を作成
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 特異値分解を実行
U, s, Vt = svd(A)

print("U行列:", U)
print("特異値:", s)
print("V転置行列:", Vt)

[実行結果]

U行列: [[-0.21483724  0.88723069  0.40824829]
 [-0.52058739  0.24964395 -0.81649658]
 [-0.82633754 -0.38794278  0.40824829]]
特異値: [1.68481034e+01 1.06836951e+00 3.33475287e-16]
V転置行列: [[-0.47967118 -0.57236779 -0.66506441]
 [-0.77669099 -0.07568647  0.62531805]
 [-0.40824829  0.81649658 -0.40824829]]

5. 高度な統計解析

SciPystats モジュールを使用して、時間系列データの解析ベイズ統計を行うことができます。

時系列解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import numpy as np
from scipy import stats

# ランダムな時間系列データを生成
np.random.seed(0)
data = np.random.normal(loc=0, scale=1, size=100)

# 移動平均を計算
moving_avg = np.convolve(data, np.ones(10)/10, mode='valid')

# 自己相関関数を計算
autocorrelation = np.correlate(data, data, mode='full')[len(data)-1:]

print("移動平均:", moving_avg)
print("自己相関関数:", autocorrelation)

[実行結果]

移動平均: [ 0.73802317  0.57602229  0.68143392  0.6596639   0.44774208  0.3053726
  0.43646782  0.49086689  0.48548678  0.52711544  0.40064602  0.13094268
  0.05087719  0.06121703 -0.02516697  0.15742217 -0.02138183 -0.16621389
 -0.16441645 -0.0424453   0.18990016  0.46069388  0.43314827  0.25792608
  0.13406293 -0.12770374  0.03336772  0.15182094  0.29077731  0.0987667
 -0.07839945 -0.19874949 -0.37856753 -0.46041598 -0.06725879 -0.08343279
 -0.14287512 -0.39118373 -0.43367268 -0.55632978 -0.54737353 -0.53206489
 -0.35137285 -0.23182634 -0.5449671  -0.4968201  -0.41017949 -0.27824823
 -0.32575008 -0.2277925  -0.24279259 -0.22049198 -0.29513754 -0.32537166
 -0.3799367  -0.35937586 -0.44238714 -0.6120587  -0.59602766 -0.62332529
 -0.58185663 -0.44170153 -0.39284793 -0.19759323 -0.14844755 -0.125956
 -0.15425892 -0.0783188  -0.18248199 -0.12290741 -0.12248541 -0.31190945
 -0.23472509 -0.30209892 -0.33224071 -0.22364965  0.03442028  0.23937795
  0.27927043  0.20335042  0.30317906  0.37937635  0.41153821  0.38579946
  0.63708773  0.52389916  0.40496755  0.2881396   0.48471913  0.6044856
  0.53923937]
自己相関関数: [ 1.01940362e+02  7.49394405e+00  1.40845443e+01  3.58390554e+00
 -3.45126186e+00  2.75479126e+00  7.21228414e+00  1.90464843e+01
  1.81499912e+01 -1.14537349e+01  8.20087810e+00 -5.48971674e+00
  1.78665772e+01  2.09206234e+01  8.03065262e+00  1.98039809e+01
 -1.19182254e+01 -8.22069298e+00 -3.18112877e+00 -3.32358189e+00
  3.23453119e+00  9.15759601e+00 -2.51764995e+00 -7.51507739e+00
 -6.84979280e+00  1.08431723e+01 -2.73024055e+00  9.81641978e+00
  4.20214895e+00 -7.77522154e+00 -8.94095549e+00 -1.00156014e+01
 -1.10844591e+01  1.98310807e+00 -4.16775994e+00  2.07431019e-01
 -8.32963819e+00 -1.46067197e+01 -1.16028816e+01 -1.33531273e+01
 -5.40071130e+00 -1.88558779e+00 -6.44695942e+00  7.44795715e+00
 -1.46116671e+01 -1.38715550e+01 -1.66644680e+00 -1.53310746e+01
  4.28389398e+00 -1.42754227e+01 -3.03492565e+00 -1.49111353e+01
 -1.78346315e+01 -5.28930824e+00 -1.94049240e+00 -4.06141305e-01
  1.35520604e+00 -3.43655113e-01  1.59358538e+00 -1.70514264e+01
 -1.16362199e+00 -1.13763563e-01 -9.68419501e+00  3.39262432e+00
 -1.14316574e+01 -6.29963920e+00 -9.18539370e+00  1.13648959e+00
  8.32207118e+00  4.75767810e+00  5.10329604e+00  4.98252744e-01
 -6.57950487e+00  2.09747684e+00 -4.23232352e+00  4.38111793e+00
 -3.68216528e+00 -6.61917365e+00  4.09727850e+00 -1.21027998e-02
 -3.27795161e-01  1.00630679e+01  1.01709114e+01  6.74877802e+00
  2.41041134e+00  6.44932432e+00  4.42227923e+00  3.01520536e+00
  1.87907486e+00  5.43300645e+00  2.03698005e+00  6.93959044e+00
  1.02441284e+00  6.17363816e+00  4.76777152e+00  4.03366789e+00
  1.75818045e+00  3.59459608e+00  3.84738516e-01  7.09130280e-01]

ベイズ統計

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np
from scipy.stats import beta

# 事前分布を設定
a, b = 2, 2
x = np.linspace(0, 1, 100)

# ベータ分布の事前分布をプロット
prior = beta.pdf(x, a, b)

# 観測データを設定
observed_successes = 8
observed_failures = 2

# 事後分布を計算
posterior = beta.pdf(x, a + observed_successes, b + observed_failures)

# 結果をプロット
import matplotlib.pyplot as plt
plt.plot(x, prior, label='Prior')
plt.plot(x, posterior, label='Posterior')
plt.legend()
plt.show()

[実行結果]


これらの高度な使用例は、SciPyの豊富な機能を活用するための一部に過ぎません。

SciPyは、科学技術計算の多くの分野に対応しており、複雑な問題を効率的に解決するための強力なツールセットを提供しています。

Pandasの高度な使い方

Pandasの高度な使い方

Pandasの高度な使い方として、以下のようなテクニックがあります。

これらはデータの前処理分析可視化に役立つ機能です。

1. 高度なデータフィルタリング

条件付きのフィルタリング複数条件のフィルタリングを行うことができます。

1
2
3
4
5
6
7
8
9
import pandas as pd

# サンプルデータの作成
data = {'A': [10, 20, 30, 40], 'B': [100, 200, 300, 400]}
df = pd.DataFrame(data)

# A列の値が20以上かつB列の値が300以下の行をフィルタリング
df_filtered = df[(df['A'] >= 20) & (df['B'] <= 300)]
print(df_filtered)

[実行結果]

    A    B
1  20  200
2  30  300

2. `apply`と`lambda`を使ったデータ変換

Pandasapply関数とlambdaを使ってカスタム関数を適用できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np

# カスタム関数を定義
def custom_function(x):
return x ** 2

# A列にカスタム関数を適用
df['A_squared'] = df['A'].apply(custom_function)

# B列にlambda関数を適用
df['B_log'] = df['B'].apply(lambda x: x if x == 0 else np.log(x))

print(df)

[実行結果]

    A    B  A_squared     B_log
0  10  100        100  4.605170
1  20  200        400  5.298317
2  30  300        900  5.703782
3  40  400       1600  5.991465

3. 時系列データの操作

Pandas時系列データの操作に強力な機能を提供します。

1
2
3
4
5
6
7
8
9
10
11
12
# サンプルの時系列データの作成
date_rng = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')
df_time = pd.DataFrame(date_rng, columns=['date'])
df_time['data'] = np.random.randint(0, 100, size=(len(date_rng)))

# date列をインデックスに設定
df_time.set_index('date', inplace=True)

# リサンプリングして月ごとの平均を計算
df_monthly_mean = df_time.resample('M').mean()

print(df_monthly_mean)

[実行結果]

            data
date            
2023-01-31  39.7

4. `groupby`と`transform`によるデータの変換

groupbytransformを組み合わせて、グループごとに変換を行います。

1
2
3
4
5
6
7
8
# サンプルデータの作成
data = {'A': ['foo', 'bar', 'foo', 'bar'], 'B': [1, 2, 3, 4], 'C': [10, 20, 30, 40]}
df = pd.DataFrame(data)

# グループごとの平均を計算してB列を標準化
df['B_normalized'] = df.groupby('A')['B'].transform(lambda x: (x - x.mean()) / x.std())

print(df)

[実行結果]

     A  B   C  B_normalized
0  foo  1  10     -0.707107
1  bar  2  20     -0.707107
2  foo  3  30      0.707107
3  bar  4  40      0.707107

5. `merge`の高度な使い方

複数のキーを使った結合や、結合方法の指定(内部結合外部結合など)を行います。

1
2
3
4
5
6
7
8
# サンプルデータの作成
df1 = pd.DataFrame({'key1': ['A', 'B', 'C'], 'key2': [1, 2, 3], 'value': [10, 20, 30]})
df2 = pd.DataFrame({'key1': ['A', 'B', 'D'], 'key2': [1, 2, 4], 'value': [100, 200, 400]})

# 複数のキーを使った内部結合
df_merged = pd.merge(df1, df2, on=['key1', 'key2'], how='inner', suffixes=('_left', '_right'))

print(df_merged)

[実行結果]

  key1  key2  value_left  value_right
0    A     1          10          100
1    B     2          20          200

6. マルチインデックス

マルチインデックスを使って階層的なデータを操作します。

1
2
3
4
5
6
7
# サンプルデータの作成
arrays = [['A', 'A', 'B', 'B'], [1, 2, 1, 2]]
index = pd.MultiIndex.from_arrays(arrays, names=('letter', 'number'))
df_multi = pd.DataFrame({'value': [10, 20, 30, 40]}, index=index)

# 特定のレベルでデータを取得
print(df_multi.xs('A', level='letter'))

[実行結果]

        value
number       
1          10
2          20

7. パイプラインを使ったデータ操作の連鎖

パイプラインを使って複数の操作を連鎖させます。

1
2
3
4
5
6
7
8
9
10
# サンプルデータの作成
df = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30]})

# パイプラインを使って操作を連鎖
df_transformed = (df
.assign(C=lambda x: x['A'] + x['B'])
.query('C > 15')
.rename(columns={'A': 'alpha', 'B': 'beta'}))

print(df_transformed)

[実行結果]

   alpha  beta   C
1      2    20  22
2      3    30  33

8. Window関数

Window関数を使ってローリング計算移動平均を計算します。

1
2
3
4
5
6
7
# サンプルデータの作成
df = pd.DataFrame({'A': range(10)})

# 移動平均の計算
df['moving_average'] = df['A'].rolling(window=3).mean()

print(df)

[実行結果]

   A  moving_average
0  0             NaN
1  1             NaN
2  2             1.0
3  3             2.0
4  4             3.0
5  5             4.0
6  6             5.0
7  7             6.0
8  8             7.0
9  9             8.0

これらの高度な使い方を活用することで、Pandasを使ったデータ操作分析がさらに効率的かつ強力になります。

Google OR-Tools

Google OR-Tools

Google OR-Toolsは、最適化の問題を解決するための強力なツールです。

OR-Toolsは、線形プログラミング整数プログラミング制約プログラミングルート最適化などの問題を解決するために使用されます。

以下に、OR-Toolsのいくつかの便利な使い方を紹介します。

1. インストール

まず、OR-Toolsをインストールします。

Pythonのパッケージマネージャーを使用してインストールできます。

1
pip install ortools

2. 線形プログラミング

線形プログラミングの問題を解決するための基本的な例です。

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
from ortools.linear_solver import pywraplp

def linear_programming_example():
# Solverを作成
solver = pywraplp.Solver.CreateSolver('GLOP')
if not solver:
return

# 変数の作成
x = solver.NumVar(0, 1, 'x')
y = solver.NumVar(0, 2, 'y')

# 制約の設定
solver.Add(x + y <= 2)

# 目的関数の設定
solver.Maximize(x + y)

# 解を求める
status = solver.Solve()

if status == pywraplp.Solver.OPTIMAL:
print('解が見つかりました:')
print('x =', x.solution_value())
print('y =', y.solution_value())
print('最適値 =', solver.Objective().Value())
else:
print('最適解が見つかりませんでした')

linear_programming_example()

[実行結果]

解が見つかりました:
x = 0.0
y = 2.0
最適値 = 2.0

3. 整数プログラミング

整数プログラミングの問題を解決するための基本的な例です。

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
from ortools.linear_solver import pywraplp

def integer_programming_example():
# Solverを作成
solver = pywraplp.Solver.CreateSolver('SCIP')
if not solver:
return

# 変数の作成
x = solver.IntVar(0, 10, 'x')
y = solver.IntVar(0, 10, 'y')

# 制約の設定
solver.Add(x + y <= 5)

# 目的関数の設定
solver.Maximize(2 * x + 3 * y)

# 解を求める
status = solver.Solve()

if status == pywraplp.Solver.OPTIMAL:
print('解が見つかりました:')
print('x =', x.solution_value())
print('y =', y.solution_value())
print('最適値 =', solver.Objective().Value())
else:
print('最適解が見つかりませんでした')

integer_programming_example()

[実行結果]

解が見つかりました:
x = 0.0
y = 5.0
最適値 = 15.0

4. ルート最適化

ルート最適化の基本的な例です。

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp

def create_data_model():
"""データを作成"""
data = {}
data['distance_matrix'] = [
[0, 9, 2, 7],
[9, 0, 6, 3],
[2, 6, 0, 4],
[7, 3, 4, 0],
]
data['num_vehicles'] = 1
data['depot'] = 0
return data

def print_solution(manager, routing, solution):
"""解を表示"""
print('Objective: {} miles'.format(solution.ObjectiveValue()))
index = routing.Start(0)
plan_output = 'Route:\n'
route_distance = 0
while not routing.IsEnd(index):
plan_output += ' {} ->'.format(manager.IndexToNode(index))
previous_index = index
index = solution.Value(routing.NextVar(index))
route_distance += routing.GetArcCostForVehicle(previous_index, index, 0)
plan_output += ' {}\n'.format(manager.IndexToNode(index))
print(plan_output)
print('Route distance: {} miles'.format(route_distance))

def main():
"""ルート最適化のメイン関数"""
# データを作成
data = create_data_model()

# ルーティングインデックスマネージャーとルーティングモデルを作成
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['depot'])
routing = pywrapcp.RoutingModel(manager)

def distance_callback(from_index, to_index):
"""距離のコールバック"""
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return data['distance_matrix'][from_node][to_node]

transit_callback_index = routing.RegisterTransitCallback(distance_callback)

# コスト関数の設定
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# 検索パラメータの設定
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)

# 解を求める
solution = routing.SolveWithParameters(search_parameters)

# 解を表示
if solution:
print_solution(manager, routing, solution)

if __name__ == '__main__':
main()

[実行結果]

Objective: 18 miles
Route:
 0 -> 2 -> 3 -> 1 -> 0

Route distance: 18 miles

5. 制約プログラミング

制約プログラミングの基本的な例です。

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
from ortools.sat.python import cp_model

def constraint_programming_example():
# モデルを作成
model = cp_model.CpModel()

# 変数の作成
x = model.NewIntVar(0, 10, 'x')
y = model.NewIntVar(0, 10, 'y')
z = model.NewIntVar(0, 10, 'z')

# 制約の設定
model.Add(x + y + z == 15)
model.Add(x > y)
model.Add(z < x + 2)

# 目的関数の設定
model.Maximize(x + 2 * y + 3 * z)

# ソルバーを作成して解を求める
solver = cp_model.CpSolver()
status = solver.Solve(model)

if status == cp_model.OPTIMAL:
print('解が見つかりました:')
print('x =', solver.Value(x))
print('y =', solver.Value(y))
print('z =', solver.Value(z))
print('最適値 =', solver.ObjectiveValue())
else:
print('最適解が見つかりませんでした')

constraint_programming_example()

[実行結果]

解が見つかりました:
x = 5
y = 4
z = 6
最適値 = 31.0

これらの例をもとに、$Google OR-Tools$を使用して様々な最適化問題を解決できます。

公式ドキュメントやチュートリアルも参考にして、さらに高度な問題に挑戦してみてください。

PuLP

PuLP

PuLPは、Python線形計画問題を解くためのオープンソースのライブラリです。

PuLPを使うと、線形最適化問題の定義と解決が簡単にできます。

ここでは、PuLPのインストール方法と基本的な使い方について説明します。

PuLPのインストール

まず、PuLPをインストールします。以下のコマンドを実行してください。

1
pip install pulp

基本的な使い方

以下は、簡単な線形計画問題を解く例です。

この例では、目的関数を最大化し、いくつかの制約条件を満たすような解を求めます。

例: 生産計画問題

ある工場では、製品Aと製品Bを生産しています。

それぞれの製品の利益と生産にかかるリソースが異なります。

工場は、利益を最大化しながら、リソースの制約を満たすように生産量を決定したいと考えています。

  1. 問題の定義:

    • 製品Aの利益は$40$ドル、製品Bの利益は$30$ドル
    • 製品Aの生産には$2$時間、製品Bの生産には$1$時間かかる
    • $1$日に利用可能な時間は$40$時間
    • 製品Aの生産には$3$単位の資源、製品Bの生産には$1$単位の資源が必要
    • $1$日に利用可能な資源は$30$単位
  2. 目的関数:

    • 利益の最大化: 40x + 30y
  3. 制約条件:

    • 時間の制約: 2x + y <= 40
    • 資源の制約: 3x + y <= 30

ここで、xは製品Aの生産量、yは製品Bの生産量です。

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pulp

# 問題の定義
problem = pulp.LpProblem("Production Optimization", pulp.LpMaximize)

# 変数の定義
x = pulp.LpVariable("A", lowBound=0, cat='Continuous')
y = pulp.LpVariable("B", lowBound=0, cat='Continuous')

# 目的関数の定義
problem += 40 * x + 30 * y, "Profit"

# 制約条件の定義
problem += 2 * x + y <= 40, "Time Constraint"
problem += 3 * x + y <= 30, "Resource Constraint"

# 問題を解く
problem.solve()

# 結果の表示
print(f"Status: {pulp.LpStatus[problem.status]}")
print(f"Optimal production of A: {x.varValue}")
print(f"Optimal production of B: {y.varValue}")
print(f"Maximum profit: {pulp.value(problem.objective)}")

出力

このコードを実行すると、最適な生産量最大利益が表示されます。

1
2
3
4
Status: Optimal
Optimal production of A: 0.0
Optimal production of B: 30.0
Maximum profit: 900.0

その他の便利な使い方

  1. 整数線形計画: 整数変数を扱う場合は、cat='Integer'を使用します。
  2. 制約の追加: 制約を追加する際は、problem +=を使って簡単に追加できます。
  3. 複数の目的関数: 複数の目的関数を持つ場合は、それぞれの重要度に応じて重み付けを行うことができます。

PuLPは、簡単な線形計画問題から複雑な制約付きの最適化問題まで幅広く対応できる強力なツールです。

株価分析 Prophet

株価分析 Prophet

実際の株価データを使ったProphetによる分析の具体例を示します。

ここでは、Yahoo Financeから取得したApple Inc.(AAPL)の過去の株価データを使って説明します。

手順

  1. データの準備:

    • Yahoo Financeなどからデータを取得する(ここでは、pandas_datareaderを使用します)。
    • データの前処理を行う。
  2. Prophetのインストールとインポート:

    1
    2
    3
    4
    5
    !pip install yfinance prophet
    import yfinance as yf
    from prophet import Prophet
    import pandas as pd
    import matplotlib.pyplot as plt
  3. データの取得とフォーマット:

    • Yahoo FinanceからAppleの株価データを取得し、Prophetが理解できるフォーマット(ds列に日付、y列に値)に変換します。
      1
      2
      3
      4
      5
      # Appleの株価データを取得
      df = yf.download('AAPL', start='2020-01-01', end='2023-01-01')
      df.reset_index(inplace=True)
      df = df[['Date', 'Close']]
      df.columns = ['ds', 'y']
  4. モデルの作成とトレーニング:

    1
    2
    model = Prophet()
    model.fit(df)
  5. 予測の作成:

    • 予測する期間のデータフレームを作成し、モデルに予測を行わせます。
      1
      2
      future = model.make_future_dataframe(periods=365)  # 365日先まで予測
      forecast = model.predict(future)
  6. 予測結果の可視化:

    1
    2
    fig = model.plot(forecast)
    plt.show()

以下に、上記手順に基づくコードを示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import yfinance as yf
from prophet import Prophet
import pandas as pd
import matplotlib.pyplot as plt

# Yahoo FinanceからAppleの株価データを取得
df = yf.download('AAPL', start='2020-01-01', end='2023-01-01')
df.reset_index(inplace=True)
df = df[['Date', 'Close']]
df.columns = ['ds', 'y']

# Prophetモデルの作成とトレーニング
model = Prophet()
model.fit(df)

# 未来のデータフレームを作成し、予測を行う
future = model.make_future_dataframe(periods=365) # 365日先まで予測
forecast = model.predict(future)

# 予測結果の可視化
fig = model.plot(forecast)
plt.show()

このコードでは、$2020$年から$2023$年のAppleの株価データを取得し、それを基に$2024$年までの株価を予測しています。

実際のデータを用いることで、Prophet予測性能実用性を具体的に確認することができます。

結果解説

[実行結果]

グラフの説明をします。

このグラフはProphetを用いてAppleの株価データを予測した結果です。

以下に各要素の説明を行います。

グラフの要素

  1. 黒い点(Observed Data):

    • 黒い点は実際の観測データ(ここではAppleの過去の株価)を示しています。
    • 日付軸($x$軸)は観測期間を示し、価格軸($y$軸)は株価を示しています。
  2. 青い線(Predicted Data):

    • 青い線はProphetによって予測された株価を示しています。
    • 観測データの終了時点から未来のデータに対して予測が行われています。
  3. 青いシェード(Uncertainty Interval):

    • 青いシェードは予測の不確実性範囲を示しています。
    • これは$95%$信頼区間を示しており、予測値がこの範囲内にある確率が高いことを意味します。

グラフの解釈

  • 過去の株価のトレンド:

    • 過去のデータ(黒い点)を見ると、株価は$2020$年から上昇トレンドを見せ、その後にいくつかのピークと谷が見られます。
    • $2021$年から$2022$年にかけて株価が特に高い値を示していますが、その後は下降トレンドに入っています。
  • 未来の株価予測:

    • 青い線とシェードを見ると、$2023$年以降の株価が予測されています。
    • 予測によると、株価は$2023$年の終わりにかけてさらに変動しながらも緩やかに下がる傾向があることが示唆されています。
    • ただし、青いシェードが広がっていることから予測の不確実性が高いことも示されています。
      このため、実際の株価が予測値から大きく外れる可能性もあることを意味します。

このグラフを元に、予測の精度やモデルの調整が必要かを評価したり、他の外部要因(経済状況、企業のニュースなど)を考慮に入れて更に詳しい分析を行うことができます。

DEAPの使い方

DEAPの使い方

DEAP(Distributed Evolutionary Algorithms in Python)は、進化的アルゴリズムを簡単に実装できる強力なPythonライブラリです。

DEAP遺伝的アルゴリズム遺伝的プログラミング進化的戦略などの進化的計算技術をサポートします。

以下にDEAPの使い方を紹介します。

インストール

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

1
pip install deap

基本的な使い方

以下は、DEAPを使って簡単な遺伝的アルゴリズムを実装する例です。

この例では、1次元の関数$ ( f(x) = x^2 ) $の最小値を見つけることを目標とします。

ステップ1: 必要なモジュールのインポート

1
2
import random
from deap import base, creator, tools, algorithms

ステップ2: 適応度と個体の定義

1
2
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

ステップ3: 個体と集団の初期化関数の定義

1
2
3
4
5
6
def create_individual():
return [random.uniform(-10, 10)]

toolbox = base.Toolbox()
toolbox.register("individual", tools.initIterate, creator.Individual, create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

ステップ4: 評価関数の定義

1
2
3
4
def evaluate(individual):
return (individual[0]**2,)

toolbox.register("evaluate", evaluate)

ステップ5: 遺伝的操作(交叉、突然変異、選択)の定義

1
2
3
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.1)
toolbox.register("select", tools.selTournament, tournsize=3)

ステップ6: メインループの実行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def main():
random.seed(42)

# 初期集団の生成
population = toolbox.population(n=300)

# 統計情報の記録
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", lambda x: sum(f[0] for f in x) / len(x))
stats.register("min", lambda x: min(f[0] for f in x))
stats.register("max", lambda x: max(f[0] for f in x))

# 遺伝的アルゴリズムの適用
population, log = algorithms.eaSimple(population, toolbox, cxpb=0.5, mutpb=0.2, ngen=40, stats=stats, verbose=True)

return population, log

if __name__ == "__main__":
population, log = main()

詳細な説明

  1. 個体と適応度の定義:

    • creator.create("FitnessMin", base.Fitness, weights=(-1.0,))最小化問題の適応度を定義します。
    • creator.create("Individual", list, fitness=creator.FitnessMin) は個体を定義します。
  2. 個体と集団の初期化:

    • toolbox.register("individual", tools.initIterate, creator.Individual, create_individual) は個体の初期化方法を定義します。
    • toolbox.register("population", tools.initRepeat, list, toolbox.individual) は集団の初期化方法を定義します。
  3. 評価関数の定義:

    • toolbox.register("evaluate", evaluate) は個体の適応度を評価する関数を登録します。
  4. 遺伝的操作の定義:

    • toolbox.register("mate", tools.cxBlend, alpha=0.5)交叉方法を定義します。
    • toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.1)突然変異方法を定義します。
    • toolbox.register("select", tools.selTournament, tournsize=3)選択方法を定義します。
  5. メインループの実行:

    • 初期集団を生成し、遺伝的アルゴリズムを適用して進化させます。
    • algorithms.eaSimple はシンプルな進化アルゴリズムを実行します。

応用例

DEAPはこの他にも、複雑な最適化問題機械学習モデルのハイパーパラメータチューニングなど、多岐にわたる応用が可能です。

進化的アルゴリズムの基本的な操作を組み合わせることで、さまざまな問題に対して効果的な解を見つけることができます。

結果解説

[実行結果]

gen    nevals    avg        min            max    
0      300       35.1213    0.000137411    99.7714
1      186       11.3106    0.000137411    142.071
2      189       2.06073    8.09465e-05    57.5294
3      182       0.311408    8.09465e-05    5.859  
4      201       0.0476175    1.43496e-07    0.537461
5      184       0.0264013    1.43496e-07    1.98748 
6      165       0.0187372    1.43496e-07    2.3111  
7      184       0.00584479    4.66901e-08    1.01736 
8      171       0.0143057     1.74459e-09    2.7338  
9      183       0.03766       3.42508e-11    3.13119 
10     196       0.0139445     2.70198e-13    1.71795 
11     174       0.00763203    9.98396e-12    2.2896  
12     183       0.0279807     2.19087e-12    3.16397 
13     172       0.0445861     5.71099e-14    4.10532 
14     197       0.0404401     9.19872e-16    4.16248 
15     193       0.00869942    1.0381e-16     1.68343 
16     168       0.017233      4.54004e-18    4.39632 
17     190       0.0282809     4.54004e-18    3.99426 
18     181       0.00581783    4.54004e-18    1.35411 
19     171       0.0169429     1.1955e-20     1.48987 
20     178       0.00411972    1.1955e-20     0.942579
21     168       1.49487e-05    1.1955e-20     0.00448462
22     162       0.0339901      2.64989e-24    3.10837   
23     190       0.0281804      2.64989e-24    2.458     
24     183       0.00136639     2.64989e-24    0.406396  
25     192       0.00143387     2.64989e-24    0.415259  
26     184       0.0123394      2.64989e-24    1.53045   
27     181       0.0065535      1.01205e-25    0.865262  
28     174       0.0104235      1.01205e-25    3.07322   
29     165       0.0185256      3.81818e-26    2.29195   
30     194       0.0189607      8.40103e-28    2.17665   
31     177       0.022405       5.31745e-28    4.24237   
32     168       0.00344535     1.27978e-30    0.688723  
33     198       0.0134132      1.27978e-30    1.96295   
34     196       0.0149899      2.52342e-33    2.83645   
35     174       0.0222204      8.61228e-34    3.91442   
36     199       0.0133543      2.52342e-33    2.43717   
37     186       0.0186542      1.59323e-33    2.38034   
38     185       0.0256567      9.92576e-36    4.04765   
39     182       0.0165402      9.92576e-36    3.32881   
40     171       0.00423898     8.06979e-36    0.47821   

この結果は、DEAPを用いて進化的アルゴリズムを実行した際の世代ごとの統計情報です。

各世代(gen)において、評価された個体数(nevals)、平均適応度(avg)、最小適応度(min)、最大適応度(max)が記録されています。

以下はそれぞれの項目についての説明です。

各項目の説明

  1. gen: 世代数。進化のステップを示します。
  2. nevals: 評価された個体の数。その世代で評価された個体の数を示します。
  3. avg: 平均適応度。その世代の個体の平均適応度(この場合、xの2乗の平均)です。
  4. min: 最小適応度。その世代の中で最も小さい適応度(最小値)を示します。
  5. max: 最大適応度。その世代の中で最も大きい適応度(最大値)を示します。

結果の解説

初期世代(世代0)

  • avg: $35.1213$
  • min: $0.000137411$
  • max: $99.7714$

初期集団では適応度の平均が$35.1213$で、最小値が$0.000137411$、最大値が$99.7714$です。
このことから、初期集団には非常に幅広い適応度の個体が含まれていることがわかります。

世代ごとの進化

進化が進むにつれて、適応度の平均値(avg)は減少していきます。
これは、進化が進むことで適応度が改善されている(より良い個体が選択され、交叉されている)ことを示しています。

例えば、世代$3$では、

  • avg: $0.311408$
  • min: $0.0000809465$
  • max: $5.859$

適応度の平均が$0.311408$に減少し、最小値も$0.0000809465$と非常に小さくなっています。
進化の過程で良好な個体が選択され続けていることがわかります。

最終世代(世代$40$)

  • avg: $0.00423898$
  • min: $8.06979e-36$
  • max: $0.47821$

最終世代では、平均適応度が$0.00423898$まで減少し、最小値は$8.06979e-36$とほぼゼロに近づいています。
これは、進化的アルゴリズムが目標とする適応度関数の最小値を非常に効果的に探索したことを示しています。

まとめ

この結果から、DEAPを用いた進化的アルゴリズムが適応度関数の最小化問題を効率的に解決できたことがわかります。

世代を重ねるごとに適応度が改善され、最終的には非常に小さな適応度の個体が得られました。