0. はじめに
分類モデルの構築、評価について、
理論・実装を合わせて整理するために投稿いたしました。
学習モデル・評価関数等一部を更新する等で、ご利用いただければ幸いです。
1. データセットの可視化
- 学習データ
-
x:説明変数 $[(x_{11},x_{12},...x_{1M}),...(x_{N1}...x_{NM}) ]$
-
y:目的変数 $y_1, y_2, ...y_N$
- N:サンプル
- M:説明変数の数
-
\begin{pmatrix}
x_{11} &x_{12} & ... &x_{1M} \\
x_{21} &x_{22} & ... &x_{2M} \\
: & & & \\
x_{N1} &x_{N2} & ... &x_{NM}
\end{pmatrix}
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
1.1. 表
iris_df = sns.load_dataset('iris') # データセットの読み込み
iris_df.head()
1.2. 散布図
sns.pairplot(iris_df, hue='species')
#2. 学習
##2.0.訓練データ(train)・テストデータ(test)に分割する
from sklearn.model_selection import train_test_split
X = iris_df[['sepal_length','sepal_width','petal_length','petal_width']] # 説明変数
Y = iris_df['species']
#訓練データ80%、テストデータ20%に分割。
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size = 0.2, random_state = 0) # 80%のデータを学
##2.1. ロジスティック回帰
モデル : $Y_{pred} = \pi(\alpha X + \beta) $
ロジスティック関数:$\pi = \frac{e^x}{(1 + e^x)}$
from sklearn.linear_model import LogisticRegression
model_LR = LogisticRegression() # ロジスティック回帰モデルのインスタンスを作成
model_LR.fit(X_train.to_numpy(), Y_train.to_numpy()) # ロジスティック回帰モデルの重みを学習
2.2. サポートベクターマシン
マージン(識別境界と、識別境界と最短距離のサンプル との距離)を最大化
from sklearn.svm import LinearSVC
model_LinearSVC = LinearSVC() # サポートベクターマシンのインスタンス生成
model_LinearSVC.fit(X_train, Y_train) # サポートベクターマシンモデルの重みを学習
2.3. Kmeans
- クラスター数KとK個の重心を決める。
- クラスター(重心)の位置が変化しなくなるまで、以下を繰返す。
- 各サンプルX_i とクラスターK(重心)との距離を計算。
- で計算した距離が最も近いクラスターに、各サンプルを割り当てる。
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=len(iris_df["species"].unique()))
model_kmeans = kmeans.fit(X)
2.4.ニューラルネットワーク
ニューラルネットワークの学習
- 目的:損失関数を最小化するような、モデルのパラメータ$W$を求める。
- 損失関数: $L = (正解 - モデルによる予測値)^2$
- モデルによる予測値: $activation( W_2 activation(W_1 X))$ ※中間層2つの時
- activation:活性化関数
- $W_i$: 中間層iの重みベクトル
- X:説明変数
MLPClassifier のパラメータについて
-
hidden_layer_size: 中間層の層数および、各中間層のニューロン数
- (50,50,50)の場合、中間層は3つ。各中間層のニューロン数は、それぞれ50。
-
activation: 中間層の活性化関数
- identity(恒等関数): $f(x) = x$
- relu(ReLU関数):
$f(x) = \begin{cases}
0 & (x \leq 0) \
x & (x > 0)
\end{cases}
$ - logistic(シグモイド関数): $f(x) = \frac{e^x}{1+e^x}$
-
solver:重みWを最適化する方法
- sgd: 確率的勾配降下法
- adam:
- lbfgb:準ニュートン法
-
max_iter:学習反復回数の、"最大回数"
from sklearn.neural_network import MLPClassifier
model_NN = MLPClassifier(hidden_layer_sizes=(50,50,50), max_iter=1000, activation = "relu", solver = "sgd")
model_NN.fit(X_train, Y_train)
3. 識別境界の可視化
3.3 K近傍法 (教師なし学習の一種)
#iris_df = iris_df[["petal_length","petal_width", "species"]]
iris_df["cluster"] = model_kmeans.labels_
markers = ["o", "x", "+"] #正解ラベルごとに図形を変える。
pos = 0
for i in iris_df["cluster"].unique():
tmp = iris_df.loc[iris_df["cluster"] == i]
#plt.scatter(tmp.loc["petal_length"], tmp.loc["petal_width"])
plt.scatter(tmp["petal_length"], tmp["petal_width"], marker = markers[pos])
pos += 1
plt.title("Scatter Plot of Kmeans")
plt.xlabel("petal_length")
plt.ylabel("petal_width")
plt.show()
4. 評価指標ごとの精度
4.1. 評価指標を計算
評価指標
- confusion_matrix(混同行列)
- logloss (交差エントロピー誤差)
confusion_matrix
Predict(学習モデルの予想) | |||
---|---|---|---|
Negative | Positive | ||
True(正解) | Negative | TN | FP |
Positive | FN | TP |
- TP(True Positive): モデルがPositiveと予想し、正解(True)
- TN(True Negative): モデルがNegativeと予想し、正解(True)
- FP(True Positive): モデルがPositiveと予想し、不正解(False)
- FN(True Negative): モデルがNegativeと予想し、不正解(False)
交差エントロピー誤差 $H(x)$
$H(p, q) = - \sum_{1}^{クラス数} p(x)log(q(x)) $
- p: 正解$y_{true}$の確率分布
- q: 学習モデルが予測した目的変数の値$y_{predict}$の確率分布
p:[1.0,0.0,0.0], q:[0.7, 0.2,0.1] の場合
$ H(p, q) = - (1.0 \times \log(0.7) + 0.0 \times 0.2 + 0.0 \times 0.1) $
= - log(0.7)
from sklearn.metrics import accuracy_score
from sklearn.metrics import log_loss
from sklearn.preprocessing import OneHotEncoder
from sklearn.metrics import confusion_matrix
#評価のため、目的変数の値を数値型へ変換する。
Y_test = Y_test.replace({"virginica":0,"setosa":1,"versicolor":2})
Y_test = pd.DataFrame(Y_test)
#logloss計算用に、目的変数の値をOneHot表現に変換。予測値(Y_pred*)のみ変換。
encoder_OneHot = OneHotEncoder(categories="auto", sparse=False, dtype=np.float32)
Y_test_OneHot = encoder_OneHot.fit_transform(Y_test)
#ロジスティック回帰
Y_pred_LR = model_LR.predict(X_test)
Y_pred_LR = pd.DataFrame(Y_pred_LR).replace({"virginica":0,"setosa":1,"versicolor":2})
Y_pred_LR_OneHot = encoder_OneHot.fit_transform(Y_pred_LR)
cm_LR = confusion_matrix(Y_test, Y_pred_LR)
logloss_LR = log_loss(Y_test, Y_pred_LR_OneHot)
#サポートベクターマシン
Y_pred_LinearSVC = model_LinearSVC.predict(X_test)
Y_pred_LinearSVC = pd.DataFrame(Y_pred_LinearSVC).replace({"virginica":0,"setosa":1,"versicolor":2})
Y_pred_LinearSVC_OneHot = encoder_OneHot.fit_transform(Y_pred_LinearSVC)
cm_LinearSVC = confusion_matrix(Y_test, Y_pred_LinearSVC)
logloss_LinearSVC = log_loss(Y_test, Y_pred_LinearSVC_OneHot)
#kmeans
Y_pred_kmeans = model_kmeans.predict(X_test)
Y_pred_kmeans = pd.DataFrame(Y_pred_kmeans)
Y_pred_kmeans_OneHot = encoder_OneHot.fit_transform(Y_pred_kmeans)
cm_kmeans = confusion_matrix(Y_test, Y_pred_kmeans)
logloss_kmeans = log_loss(Y_test, Y_pred_kmeans_OneHot)
#ニューラルネットワーク
Y_pred_NN = model_NN.predict(X_test)
Y_pred_NN = pd.DataFrame(Y_pred_NN).replace({"virginica":0,"setosa":1,"versicolor":2})
Y_pred_NN = pd.DataFrame(Y_pred_NN)
Y_pred_NN_OneHot = encoder_OneHot.fit_transform(Y_pred_NN)
cm_NN = confusion_matrix(Y_test, Y_pred_NN)
logloss_NN = log_loss(Y_test, Y_pred_NN_OneHot)
4.2.評価結果を可視化
4.2.1. Confusion_matrix (混同行列)
ロジスティック回帰
cm_LR = pd.DataFrame(data=cm_LR, index=["virginica", "setosa", "versicolor"],
columns=["virginica", "setosa", "versicolor"])
sns.heatmap(cm_LR, square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel("True Label", fontsize=15)
plt.ylabel("Predict", fontsize=15)
plt.show()
サポートベクターマシン
cm_LR = pd.DataFrame(data=cm_LinearSVC, index=["virginica", "setosa", "versicolor"],
columns=["virginica", "setosa", "versicolor"])
sns.heatmap(cm_LinearSVC, square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel("True Label", fontsize=15)
plt.ylabel("Predict", fontsize=15)
plt.show()
####ニューラルネットワーク
cm_NN = pd.DataFrame(data=cm_NN, index=["virginica", "setosa", "versicolor"],
columns=["virginica", "setosa", "versicolor"])
sns.heatmap(cm_NN, square=True, cbar=True, annot=True, cmap='Blues')
plt.xlabel("True Label", fontsize=15)
plt.ylabel("Predict", fontsize=15)
plt.show()
4.2.2. Logloss
logloss = pd.DataFrame([[logloss_LR],[logloss_LinearSVC],[logloss_kmeans],[logloss_NN]],
index = ["LR","LinearSVC","kmeans","logloss_NN"],columns = ["logloss"])
logloss