本記事では、PyCaretを用いてベストな回帰モデルを自動で作成する雛形コードと、作成した複数の回帰モデル(バイナリファイル)を利用して、Optunaを用いて多目的最適化を行う雛形コードを載せました。
最終的には、複数の目的変数に対して最小値or最大値を探索することで、下図のようにパレート解を取得します。csvファイルにも出力する仕様にしています。

例題として使用したデータは、機械学習の回帰分析用でお馴染みの「ボストンデータセット」です(下図例)。本来は、目的変数は「PRICE」でその他が説明変数です。しかし、本記事では多目的最適化の例とするためにもうひとつの目的変数として、「RM」の2つとしました。そして、説明変数は便宜上 ['LSTAT', 'PTRATIO', 'INDUS', 'DIS', 'AGE', 'CHAS']の6つとしました。

csvファイルとして作成する例は次のリンク先です。Python scikit-learn付属のボストン市の住宅価格データ(Boston house prices dataset)をcsvファイル化する - PythonとVBAで世の中を便利にする
◆以下、本コード実施例について説明します。
本コードを実行すると下図のようにヒストグラムを作成します。

また、下図のように行列散布図を作成します。

そして、下図のようにして、ベストな回帰モデルを自動で選定します。

その結果、下図のように作成した回帰モデルの相関性を可視化します。

また、作成した回帰モデルの誤差も図示します。

更に、目的変数に対する感度の高い説明変数のランキングを作成します。

最終的には、下図のようにパレート解をcsvファイルで取得します。これを図示したのが冒頭のグラフです。

■本プログラム
▼PyCaretで回帰モデルを作成する
目的変数の数だけ回帰モデルを作成します。目的変数名はコード中の「target_name」で指定します。これを目的変数の数だけ実行して、回帰モデル「best_model_***.pkl」をバイナリファイルで作成します(***は目的変数名です)。
import pandas as pd
file_path = './boston_XYdata.csv'
df = pd.read_csv(file_path,
sep=',',
skiprows=0,
header=0,
encoding='utf-8')
print(df)
featrure_name_list = ['LSTAT', 'PTRATIO', 'INDUS', 'DIS', 'AGE', 'CHAS']
target_name = 'PRICE'
dataset_name_list = featrure_name_list.copy()
dataset_name_list.append(target_name)
print(dataset_name_list)
df2 = df[dataset_name_list]
print(df2)
print(df2.isna().sum())
DF = df2.dropna()
print(DF)
DF_describe = DF.describe().T
DF_describe
import matplotlib
matplotlib.use('Agg')
from matplotlib import pyplot as plt
DF.hist()
plt.tight_layout()
plt.savefig('graph_histogram_' + target_name + '.png')
plt.close()
import seaborn as sns
sns.set_context('talk')
ax = sns.pairplot(
DF,
kind = 'reg',
markers = '.',
diag_kind = 'kde',
diag_kws = dict(shade = True),
)
plt.savefig('graph_pairplot_' + target_name + '.png')
plt.close()
from pycaret.regression import *
set_data = setup(
data = DF,
normalize = False,
train_size = 0.7,
session_id = 1,
target = target_name,
categorical_features=['CHAS'],
numeric_features = ['LSTAT', 'PTRATIO', 'INDUS', 'DIS', 'AGE'],
silent=True,
)
top5 = compare_models(n_select = 5,
sort = 'MAE',
verbose = False)
tuned_top5 = [tune_model(i, verbose = False) for i in top5]
best = automl(optimize = 'MAE')
predict_model(best)
plot_model(best, plot = 'error')
plt.savefig('graph_error_' + target_name + '.png')
plt.close()
plot_model(best, plot = 'residuals')
plt.savefig('graph_residuals_' + target_name + '.png')
plt.close()
plot_model(best, plot = 'feature')
plt.savefig('graph_feature_' + target_name + '.png')
plt.close()
plot_model(best, plot = 'parameter')
plt.savefig('graph_parameter_' + target_name + '.png')
plt.close()
try:
interpret_model(best)
plt.savefig('graph_interpret_model_' + target_name + '.png')
plt.close()
except:
pass
save_model(best, model_name = 'best_model_' + target_name)
▼Optunaによる多目的最適化でパレート解を取得する
上記コードで作成した複数の回帰モデル「best_model_***.pkl」を目的関数とします。Optunaの多目的最適化で、各々の最小値or最大値を探索します。
from pycaret.regression import *
target_y1_name = 'PRICE'
target_y2_name = 'RM'
load_model_y1 = load_model('best_model_' + target_y1_name)
load_model_y2 = load_model('best_model_' + target_y2_name)
print(load_model_y1)
print(load_model_y2)
import optuna
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
def objective(trial):
lstat = trial.suggest_float('LSTAT', 1.7, 38)
ptratio = trial.suggest_float('PTRATIO', 12.6, 22)
indus = trial.suggest_float('INDUS', 0.4, 24)
dis = trial.suggest_float('DIS', 1.1, 12)
age = trial.suggest_float('AGE', 3, 100)
chas = trial.suggest_categorical('CHAS', ['0', '1'])
df = pd.DataFrame([(lstat, ptratio, indus, dis, age, chas)],
columns= ['LSTAT', 'PTRATIO', 'INDUS', 'DIS', 'AGE', 'CHAS'])
predict_y1 = predict_model(load_model_y1, data=df).values.tolist()[0][-1]
predict_y2 = predict_model(load_model_y2, data=df).values.tolist()[0][-1]
return predict_y1, predict_y2
study = optuna.multi_objective.create_study(
directions=["minimize", "maximize"],
sampler=optuna.multi_objective.samplers.NSGAIIMultiObjectiveSampler(seed = 1)
)
study.optimize(objective, n_trials=200)
trials = {str(trial.values): trial for trial in study.get_trials()}
trials = list(trials.values())
y1_all_list = []
y2_all_list = []
for i, trial in enumerate(trials, start=1):
y1_all_list.append(trial.values[0])
y2_all_list.append(trial.values[1])
trials = {str(trial.values): trial for trial in study.get_pareto_front_trials()}
trials = list(trials.values())
trials.sort(key=lambda t: t.values)
y1_list = []
y2_list = []
with open('pareto_data.csv', 'w') as f:
for i, trial in enumerate(trials, start=1):
if i == 1:
columns_name_list = ['trial_no', target_y1_name, target_y2_name]
columns_name_str = ','.join(columns_name_list)
data_list = []
data_list.append(trial.number)
y1_value = trial.values[0]
y2_value = trial.values[1]
y1_list.append(y1_value)
y2_list.append(y2_value)
data_list.append(y1_value)
data_list.append(y2_value)
for key, value in trial.params.items():
data_list.append(value)
if i == 1:
columns_name_str += ',' + key
if i == 1:
f.write(columns_name_str + '\n')
data_list = list(map(str, data_list))
data_list_str = ','.join(data_list)
f.write(data_list_str + '\n')
plt.rcParams["font.size"] = 16
plt.figure(dpi=120)
plt.title("multiobjective optimization")
plt.xlabel(target_y1_name)
plt.ylabel(target_y2_name)
plt.grid()
#plt.scatter(y1_all_list, y2_all_list, c='blue', label='all trials')
#plt.scatter(y1_list, y2_list, c='red', label='pareto front')
plt.scatter(y1_all_list, y2_all_list, facecolor='None', edgecolors='blue', label='all trials')
plt.scatter(y1_list, y2_list, facecolor='None', edgecolors='red', label='pareto front')
plt.legend()
plt.tight_layout()
plt.savefig("pareto_graph.png")
plt.close()
以上
<広告>
リンク