0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Classification評価指標の表示あれこれ

Posted at

はじめに

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行表示

決定木モデル適用&ハイパーパラメーターチューニング

決定木→GridSearch→score表示
#@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('\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] を選択し、実行します。
image.png

実行すると、以下の混同行列が表示されます。

array([[88, 2],
   [11, 42]])

ちょっと、シンプル過ぎる感じなので、データフレーム表示に変えてみましょう。

混同行列をデータフレーム表示
cm = confusion_matrix(y_test,y_test_pred)
cm = pd.DataFrame(data = cm)
display(cm)

image.png
すこし見やすくなりました。

次は、行ラベル・列ラベル名を入れてみましょう。

混同行列をデータフレーム表示(行列名追加)
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

image.png
少しわかりやすくなりました。

次は、混同行列をヒートマップ表示に変えてみます。

混同行列をヒートマップ表示
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);

image.png
グラフサイズを小さくしたこともありますが、かわいいですね。
ヒートマップ表示にした方が、見やすく、わかりやすいです。

次は、yellowbrickライブラリで混同行列(ヒートマップ)を描いてみます。

混同行列を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();

image.png
タイトルもついていい感じです。

yellowbrickは、Classification reportのヒートマップ表示にも対応していますので、次は 混同行列とClassification reportをセットで描いてみます。

混同行列とClassification reportを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.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

image.png
視認性があがりましたね。
わずかなことですが、ただただ見た目をよくする...ということではなく、把握・判断しやすくするという意味での視覚化は大事と思います。

最後に

yellowbrick はいいですね。
よろしければ、以下の記事も参照ください。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?