# ’20/01/19更新 例(4)を追記
本記事ではPythonに限らない話である。例のためPythonの多目的最適化のフレームワーク「Platypus」を挙げると、最大化問題を解くProblem.MAXIMIZEと、最小化問題を解くProblem.MINIMIZEの二つがある。
最大化問題とは、例えばy=f(x)において、yが最大となるxを探索すること。
最小化問題は、その逆でyが最小となるxを探索することである。
その他の最適化のライブラリにおいても、自分のやりたいことの例題が少ない(見つけられない)かったりするが、最大化or最小化できれば下記のように考えて目的関数を設定することで、最適化問題を解くことができる。
例(1) f(x)の目的値を0にしたい場合
→目的関数をy=1/f(x)として、yを最大化問題として解けばf(x)は0に近づく。それは式変形してf(x)=1/yにより分かる。
例(2) f(x)の目的値を負側から0にしたい場合
→目的関数をy=-1/f(x)として、yを最大化問題として解けばf(x)は負側から0に近づく。それは式変形してf(x)=-1/yより分かる。
例(3) f(x)の目的値を3にしたい場合
→目的関数をy=3-f(x)として、yを最小化問題として解けばf(x)は3に近づく。それは式変形してf(x)=3-yよりわかる。ここで、もしy(≒f(x))がマイナス(-)を探索する可能性がある場合は二乗を取ったりしても良い。しかし、パレート解(得られる複数の最適解)から負の解は異常だと判別出来て振るいに掛けられることは可能なため、特に意識しすぎなくともよいと思う。
例(4) 最大化したいが指定方法が最小化問題しかない場合
→例えば、アルゴリズムNSGAⅢはProblem.MINIMIZEのみ指定できる。このような場合は目的関数をy=-1 × f(x)として、マイナスを掛けることでyを最小化問題として解けばf(x)は負側無限へ近づく。そして、得られた結果に対して、再びー1を掛け戻せば、所望の最大値の結果を得られることになる。
■本記事の例(3)のコード例を下記に示す
目的関数2について腹囲の回帰式をそのまま用いるのではなくて、「目的関数=75ー回帰式」、objective_function2 = 75 - myfunc2.interaction_ver_func(Chins, Situps, Jumps)として、腹囲の目的値を75に設定している。
import sys
sys.path.append(".")
import Weight_LinearRegression_interaction_ver_module as myfunc1
import Waist_LinearRegression_interaction_ver_module as myfunc2
import Pulse_LinearRegression_interaction_ver_module as myfunc3
from platypus import NSGAII, Problem, Real, Integer
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import seaborn as sns
def my_function_from_module(vars):
Chins = vars[0]
Situps = vars[1]
Jumps = vars[2]
objective_function1 = myfunc1.interaction_ver_func(Chins, Situps, Jumps)
objective_function2 = 75 - myfunc2.interaction_ver_func(Chins, Situps, Jumps)
objective_function3 = myfunc3.interaction_ver_func(Chins, Situps, Jumps)
return [objective_function1,
objective_function2,
objective_function3]
def plot_scatter(algorithm, out_file_name, my_color):
my_file_name = out_file_name + '_NSGAII'
x_list = [s.objectives[0] for s in algorithm.result]
y_list = [75 - s.objectives[1] for s in algorithm.result]
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(1,1,1)
ax.set_title('Multi-objective optimization', fontsize=14)
ax.set_xlabel(my_xlabel, fontsize=16)
ax.set_ylabel(my_ylabel, fontsize=16)
if my_xrange:
ax.set_xlim([my_xrange[0], my_xrange[1]])
if my_yrange:
ax.set_ylim([my_yrange[0], my_yrange[1]])
ax.scatter(x_list, y_list, facecolors='none', edgecolors=my_color,
label="NSGAII" + '\n Pareto frontier')
ax.legend(loc='best', fontsize=14)
ax.grid(which='both')
ax.tick_params(labelsize=14)
plt.tight_layout()
plt.savefig(my_file_name + '_Pareto_frontier.png')
plt.close()
def plot_matrix_scatter(label, DF, my_sequential_colormap):
print("plot_matrix_scatter ...")
sns.set(style="ticks", font_scale=1.2, palette=my_sequential_colormap, color_codes=True)
g = sns.pairplot(DF, diag_kind="hist")
g.fig.suptitle(label)
g.fig.subplots_adjust(top=0.9)
plt.grid(True)
plt.savefig(label + "_Matrix_scatter.png")
plt.close()
def create_Summary_data(Chins,
Situps,
Jumps,
algorithm, my_sequential_colormap):
my_file_name = out_file_name + '_NSGAII'
column_name_list = ['Chins', 'Situps', 'Jumps',
'Weight', 'Waist', 'Pulse']
column_name_list = ','.join(column_name_list)
row_list=[]
with open(my_file_name + '.csv', 'w') as f:
f.writelines(column_name_list)
f.write('\n')
for i in range(len(algorithm.result)):
row_list.append(Chins.decode(algorithm.result[i].variables[0]))
row_list.append(Situps.decode(algorithm.result[i].variables[1]))
row_list.append(Jumps.decode(algorithm.result[i].variables[2]))
row_list.extend(algorithm.result[i].objectives[:])
row_list[-2] = 75 - row_list[-2]
print('NSGAII epoch' +str(i+1) + ' -> ' + str(row_list))
row_list_str = ','.join(map(str, row_list))
f.writelines(row_list_str)
f.write('\n')
row_list=[]
df = pd.read_csv(my_file_name + '.csv')
plot_matrix_scatter(my_file_name, df, my_sequential_colormap)
def main(my_color, my_sequential_colormap):
problem = Problem(3, 3)
problem.directions[:] = [Problem.MAXIMIZE,
Problem.MINIMIZE,
Problem.MINIMIZE]
Chins = Integer(1, 17)
Situps = Integer(50, 250)
Jumps = Integer(25, 250)
problem.types[:] = [Chins,
Situps,
Jumps]
problem.function = my_function_from_module
print(problem.function)
algorithm = NSGAII(problem, 200)
algorithm.run(10000)
print(algorithm)
plot_scatter(algorithm, out_file_name, my_color)
create_Summary_data(Chins,
Situps,
Jumps,
algorithm, my_sequential_colormap)
if __name__ == '__main__':
out_file_name = 'linnerud'
my_xlabel = 'Weigth'
my_xscale = 'linear'
my_xrange = ()
my_ylabel = 'Waist'
my_yscale = 'linear'
my_yrange = (0, 100)
my_colors = ["r", "g", "b", "c", "m", "y", "k", "w"]
my_sequential_colormaps = ["spring", "summer", "autumn", "winter", 'bone',
"copper", "plasma", "magma", "cividis", "hsv"]
main(my_colors[0], my_sequential_colormaps[0])
print('finished')
下図は本コードを実行した結果である。縦軸「Waist」は目的関数2の「腹囲」である。図中の左端は「腹囲」の最適解で目的値に設定した75付近である。(ちなみに、それから右側へパレート解を描いている様子がわかる)
参考までに、本コードだけでは実行することは出来ないです。本記事の例題データで試したい場合は、下記リンク先のリンク先などで、多目的最適化をするための回帰モデル(回帰式)を各々作成しておく必要があります。
hk29.hatenablog.jp
以上
<広告>
リンク