はじめに
sklearnなら、適合率(precision)、再現率(recall)、F1スコア、正解率(accuracy)などがまとまったClassification Reportや、混同行列(ConfusionMatrix) が一発で表示できます。
とても簡単ですが、表示はとてもシンプルなので、すこし変えてみたいと思います。
実行条件など
-Google colabで実行
-データは breast cancerデータセットを使用
実行内容
データセット読込み
以下は、データセット選択のためのFormのセットです。
#@title Select_Dataset { run: "auto" }
#@markdown **<font color= "Crimson">注意</font>:かならず 実行する前に 設定してください。**</font>
dataset = 'Boston_housing :regression' #@param ['Boston_housing :regression', 'Diabetes :regression', 'Breast_cancer :binary','Titanic :binary', 'Titanic(seaborn) :binary', 'Iris :classification', 'Loan_prediction :binary','wine :classification', 'Occupancy_detection :binary', 'Upload']
以下は、選択したデータセット読込みとデータフレーム格納です。
#@title Load dataset
#ライブラリインポート
import numpy as np
import pandas as pd #データを効率的に扱うライブラリ
import seaborn as sns #視覚化ライブラリ
import warnings #警告を表示させないライブラリ
warnings.simplefilter('ignore')
'''
dataset(ドロップダウンメニュー)で選択したデータセットを読込み、データフレーム(df)に格納。
目的変数は、データフレームの最終列とし、FEATURES、TARGET、X、yを指定した後、データフレーム
に関する情報と先頭5列を表示。
任意のcsvデータを読込む場合は、datasetで'Upload'を選択。
'''
#任意のcsvデータ読込み及びデータフレーム格納、
if dataset =='Upload':
from google.colab import files
uploaded = files.upload()#Upload
target = list(uploaded.keys())[0]
df = pd.read_csv(target)
#Diabetes データセットの読込み及びデータフレーム格納、
elif dataset == "Diabetes :regression":
from sklearn.datasets import load_diabetes
diabetes = load_diabetes()
df = pd.DataFrame(diabetes.data, columns = diabetes.feature_names)
df['target'] = diabetes.target
#Breast_cancer データセットの読込み及びデータフレーム格納、
elif dataset == "Breast_cancer :binary":
from sklearn.datasets import load_breast_cancer
breast_cancer = load_breast_cancer()
df = pd.DataFrame(breast_cancer.data, columns = breast_cancer.feature_names)
df['target'] = breast_cancer.target #目的変数をカテゴリー数値とする時
#df['target'] = breast_cancer.target_names[breast_cancer.target]
#Titanic データセットの読込み及びデータフレーム格納、
elif dataset == "Titanic :binary":
data_url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
df = pd.read_csv(data_url)
#目的変数 Survived をデータフレーム最終列に移動
X = df.drop(['Survived'], axis=1)
y = df['Survived']
df = pd.concat([X, y], axis=1) #X,yを結合し、dfに格納
#Titanic(seaborn) データセットの読込み及びデータフレーム格納、
elif dataset == "Titanic(seaborn) :binary":
df = sns.load_dataset('titanic')
#重複データをカットし、目的変数 alive をデータフレーム最終列に移動
X = df.drop(['survived','pclass','embarked','who','adult_male','alive'], axis=1)
y = df['alive'] #目的変数データ
df = pd.concat([X, y], axis=1) #X,yを結合し、dfに格納
#iris データセットの読込み及びデータフレーム格納、
elif dataset == "Iris :classification":
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(iris.data, columns = iris.feature_names)
#df['target'] = iris.target #目的変数をカテゴリー数値とする時
df['target'] = iris.target_names[iris.target]
#wine データセットの読込み及びデータフレーム格納、
elif dataset == "wine :classification":
from sklearn.datasets import load_wine
wine = load_wine()
df = pd.DataFrame(wine.data, columns = wine.feature_names)
#df['target'] = wine.target #目的変数をカテゴリー数値とする時
df['target'] = wine.target_names[wine.target]
#Loan_prediction データセットの読込み及びデータフレーム格納、
elif dataset == "Loan_prediction :binary":
data_url = "https://github.com/shrikant-temburwar/Loan-Prediction-Dataset/raw/master/train.csv"
df = pd.read_csv(data_url)
#Occupancy_detection データセットの読込み及びデータフレーム格納、
elif dataset =='Occupancy_detection :binary':
data_url = 'https://raw.githubusercontent.com/hima2b4/Auto_Profiling/main/Occupancy-detection-datatest.csv'
df = pd.read_csv(data_url)
df['date'] = pd.to_datetime(df['date']) #[date]のデータ型をdatetime型に変更
#Boston データセットの読込み及びデータフレーム格納
else:
from sklearn.datasets import load_boston
boston = load_boston()
df = pd.DataFrame(boston.data, columns = boston.feature_names)
df['target'] = boston.target
#データフレーム表示
df.info(verbose=True) #データフレーム情報表示(verbose=Trueで表示数制限カット)
df.head() #データフレーム先頭5行表示
決定木モデル適用&ハイパーパラメーターチューニング
#@title **決定木実行**(GridSearchによるパラメータ最適化Ver.)
dataset_type = 'Classification' #@param ["Classification", "Regression"]
#FEATURES、TARGET、X、yを指定
FEATURES = df.columns[:-1] #説明変数のデータ項目を指定
TARGET = df.columns[-1] #目的変数のデータ項目を指定
X = df.loc[:, FEATURES] #FEATURESのすべてのデータをXに格納
y = df.loc[:, TARGET] #TARGETのすべてのデータをyに格納
#testとtrainを分割
from sklearn.model_selection import train_test_split
if dataset_type == 'Classification':
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1, stratify = y)
else:
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1, test_size=0.25)
#ライブラリインポート
from sklearn.tree import DecisionTreeRegressor
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
#GridSearch実行
if dataset_type == 'Classification':
dtv = DecisionTreeClassifier(random_state=0)
pre_dtv = dtv.fit(X_train, y_train)
print('Normal model')
print(' score \t train : %.2f,\t test : %.2f'% (
pre_dtv.score(X_train, y_train),
pre_dtv.score(X_test, y_test)))
else:
dtv = DecisionTreeRegressor(random_state=0)
pre_dtv = dtv.fit(X_train, y_train)
print('Normal model')
print(' score \t train : %.2f,\t test : %.2f'% (
pre_dtv.score(X_train, y_train),
pre_dtv.score(X_test, y_test)))
gs_dtv = GridSearchCV(dtv,
param_grid = {'max_depth': [1, 2, 3, 4, 5, 6, 7],
'min_samples_leaf':[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'min_samples_split':[2, 3, 4, 5]},
cv = 10)
gs_dtv.fit(X_train, y_train)
print('-----------------------------------------------------------------------------------------')
print('Optimal model')
print(' result\t',gs_dtv.best_estimator_)
print(' score \t train : %.2f,\t test : %.2f' % (
gs_dtv.score (X_train, y_train),
gs_dtv.score (X_test,y_test)))
print('-----------------------------------------------------------------------------------------')
評価指標算出と表示
#指標関連ライブラリインストール
from sklearn.metrics import r2_score # 決定係数
from sklearn.metrics import mean_squared_error # RMSE
from sklearn.metrics import mean_absolute_error #MAE
from sklearn.metrics import confusion_matrix #混同行列
from sklearn.metrics import classification_report #classification report
# 予測値
y_train_pred = gs_dtv.predict(X_train)
y_test_pred = gs_dtv.predict(X_test)
if dataset_type == 'Classification':
print('Confusion matrix_test')
#混同行列
confusion_matrix(y_test,y_test_pred)
print('-----------------------------------------------------------------------------------------')
print('Classification report_test')
print(classification_report(y_true=y_test, y_pred=y_test_pred))
else:
print('Regression report')
print(' RMSE\t train: %.2f,\t test: %.2f' % (
mean_squared_error(y_train, y_train_pred, squared=False),
mean_squared_error(y_test, y_test_pred, squared=False)))
print(' MAE\t train: %.2f,\t test: %.2f' % (
mean_absolute_error(y_train, y_train_pred),
mean_absolute_error(y_test, y_test_pred)))
print(' R²\t train: %.2f,\t test: %.2f' % (
r2_score(y_train, y_train_pred), # 学習
r2_score(y_test, y_test_pred) # テスト
))
print('-----------------------------------------------------------------------------------------')
※上記コードは、classification/regressionいずれにも対応しています。
前置きが長くなりましたが、今回は、breast cancerデータセット(classification)に決定木を適用し、ハイパーパラメータ調整を行った後の 混合行列表示をいろいろ変更してみたいと思います。
[Select_Dataset] で [Breast_cancer :binary] を選択し、実行します。
実行すると、以下の混同行列が表示されます。
array([[88, 2],
[11, 42]])
ちょっと、シンプル過ぎる感じなので、データフレーム表示に変えてみましょう。
cm = confusion_matrix(y_test,y_test_pred)
cm = pd.DataFrame(data = cm)
display(cm)
次は、行ラベル・列ラベル名を入れてみましょう。
cm =confusion_matrix(y_test,y_test_pred)
index1 = ["Actual_0", "Actual_1"]
columns1 =["Predicted_0", "Predicted_1"]
cm =pd.DataFrame(data = cm, index=index1, columns=columns1)
cm
次は、混同行列をヒートマップ表示に変えてみます。
sns.set(rc = {'figure.figsize':(1.5,1.5)})
sns.heatmap(confusion_matrix(y_test,y_test_pred),
square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel('Predicted', fontsize=11)
plt.ylabel('Actual', fontsize=11);
グラフサイズを小さくしたこともありますが、かわいいですね。
ヒートマップ表示にした方が、見やすく、わかりやすいです。
次は、yellowbrickライブラリで混同行列(ヒートマップ)を描いてみます。
from yellowbrick.classifier import confusion_matrix
sns.set(rc = {'figure.figsize': (1.5,1.5)})
confusion_matrix(
gs_dtv.best_estimator_,
X_train, y_train, X_test, y_test,
classes=list(y.unique()),
cmap='Blues'
)
plt.tight_layout();
yellowbrickは、Classification reportのヒートマップ表示にも対応していますので、次は 混同行列とClassification reportをセットで描いてみます。
from yellowbrick.classifier import confusion_matrix
sns.set(rc = {'figure.figsize': (1.5,1.5)})
confusion_matrix(
gs_dtv.best_estimator_,
X_train, y_train, X_test, y_test,
classes=list(y.unique()),
cmap='Blues')
plt.show()
from yellowbrick.classifier import ClassificationReport
sns.set(rc = {'figure.figsize': (4.5,2.5)})
visualizer = ClassificationReport(gs_dtv.best_estimator_, classes= list(y.unique()), support=True, cmap='Blues', fontsize=10)
visualizer.fit(X_train, y_train) # Fit the visualizer and the model
visualizer.score(X_test, y_test) # Evaluate the model on the test data
print('-----------------------------------------------------------------------------------------')
visualizer.show(); # Finalize and show the figure
視認性があがりましたね。
わずかなことですが、ただただ見た目をよくする...ということではなく、把握・判断しやすくするという意味での視覚化は大事と思います。
最後に
yellowbrick はいいですね。
よろしければ、以下の記事も参照ください。