fetch_lfw_peopleのimport

  • linearSVCを用いて分類学習を行う
  • Hold-out Validationを用いてモデルの評価を行う(train_test_split)
  • confusion matrix で指標を見てみる
In [1]:
from sklearn.datasets import fetch_lfw_people
from sklearn.model_selection import train_test_split
from sklearn import svm
from sklearn import metrics

from matplotlib import pyplot as plt

import numpy as np

from time import time

画像ロード

  • data :画像数は1140個。1画像は2914( 縦62×横47)
  • imges :画像形式の配列(各dataをreshape(62,47)した形態)
  • target :分類結果(dataを分類した場合の正解データになる値)
  • target_names : 分類結果(target)の値に対応する人物名(文字列)
In [2]:
lfw = fetch_lfw_people(data_home='./scikit_learn_data/', min_faces_per_person=100, resize=0.5)
print('lfw:',lfw.keys())
print('data:',lfw.data.shape)
print('images:',lfw.images.shape)
print('target:',lfw.target.shape)
lfw: dict_keys(['data', 'images', 'target', 'target_names', 'DESCR'])
data: (1140, 2914)
images: (1140, 62, 47)
target: (1140,)

データを学習用データと検証用データに分ける

  • 1/4を検証用データとする
In [3]:
X = lfw.data
y = lfw.target
X_train, X_test, y_train, y_test = train_test_split(lfw.data, lfw.target, test_size=0.25, random_state=0)
In [4]:
# 学習用データ数と検証用データ数
print('num of train data:', X_train.shape[0],
      '\nnum of test  data:', X_test.shape[0])
num of train data: 855 
num of test  data: 285
In [5]:
v,h = lfw.images.shape[1:3] # 画像の垂直・水平サイズを保持する
n_train = X_train.shape[0]  # 学習データ数を保持する

前回同様、そのまま学習させてみましょう。

In [6]:
linSVC=svm.LinearSVC()

学習に10秒以上かかりました。

In [7]:
t_start = time()
linSVC.fit(X_train, y_train)
print("time %0.3fs" % (time() - t_start))
time 13.549s
C:\Anaconda3\envs\AI\lib\site-packages\sklearn\svm\_base.py:947: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.
  "the number of iterations.", ConvergenceWarning)

予測は0.019秒と学習に比べると圧倒的に早いです。

モデル通りに計算するだけですから、当然と言えば当然です。

In [8]:
t_start = time()
y_pred=linSVC.predict(X_test)
print("time %0.3fs" % (time() - t_start))
time 0.019s
In [9]:
print('----------\n 検証用データの正解率',     linSVC.score(X_test,y_test))
print('----------\n classification_report\n', metrics.classification_report(y_test, y_pred, target_names=lfw.target_names))
print('----------\n confusion_matrix\n',      metrics.confusion_matrix(y_test, y_pred))
----------
 検証用データの正解率 0.8736842105263158
----------
 classification_report
                    precision    recall  f1-score   support

     Colin Powell       0.90      0.85      0.87        61
  Donald Rumsfeld       0.79      0.75      0.77        36
    George W Bush       0.88      0.94      0.91       122
Gerhard Schroeder       0.87      0.87      0.87        31
       Tony Blair       0.90      0.80      0.85        35

         accuracy                           0.87       285
        macro avg       0.87      0.84      0.85       285
     weighted avg       0.87      0.87      0.87       285

----------
 confusion_matrix
 [[ 52   3   3   1   2]
 [  3  27   5   0   1]
 [  2   3 115   2   0]
 [  0   1   3  27   0]
 [  1   0   5   1  28]]
In [10]:
plt.rcParams["figure.figsize"]=(10,10)
metrics.ConfusionMatrixDisplay(confusion_matrix=metrics.confusion_matrix(y_test, y_pred), display_labels=lfw.target_names).plot(cmap='YlGn', values_format='d')
plt.savefig('.\cmat1.jpg') 

主成分分析(Principal Component Analysis)で次元圧縮することで、学習時間が高速化を試してみました。

In [11]:
from sklearn import decomposition

PCAの結果:95%説明に必要な主成分は145個

PCAにかかった時間は約0.53s

In [12]:
pca=decomposition.PCA(n_components=0.95, svd_solver = 'full')
t_start = time()
pca.fit(X_train)
print("time %0.3fs" % (time() - t_start))
print('----------\n 主成分の数:', pca.n_components_)
time 0.530s
----------
 主成分の数: 145

学習用データ数と検証用データの次元削減にかかった時間は約0.044s

In [13]:
t_start = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t_start))
done in 0.044s

学習にかかった時間は約1.24s

In [14]:
t_start = time()
linSVC.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t_start))
done in 1.239s
C:\Anaconda3\envs\AI\lib\site-packages\sklearn\svm\_base.py:947: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations.
  "the number of iterations.", ConvergenceWarning)

検証用データの予測は0.001s

In [15]:
t_start = time()
y_pred_pca=linSVC.predict(X_test_pca)
print("time %0.3fs" % (time() - t_start))
time 0.001s
In [16]:
print('----------\n 検証用データの正解率',     linSVC.score(X_test_pca,y_test))
print('----------\n classification_report\n', metrics.classification_report(y_test, y_pred_pca, target_names=lfw.target_names))
print('----------\n confusion_matrix\n',      metrics.confusion_matrix(y_test, y_pred_pca))
----------
 検証用データの正解率 0.7052631578947368
----------
 classification_report
                    precision    recall  f1-score   support

     Colin Powell       0.62      0.75      0.68        61
  Donald Rumsfeld       0.74      0.56      0.63        36
    George W Bush       0.87      0.80      0.83       122
Gerhard Schroeder       0.51      0.68      0.58        31
       Tony Blair       0.55      0.49      0.52        35

         accuracy                           0.71       285
        macro avg       0.66      0.65      0.65       285
     weighted avg       0.72      0.71      0.71       285

----------
 confusion_matrix
 [[46  2  7  1  5]
 [ 6 20  2  6  2]
 [14  2 97  5  4]
 [ 4  1  2 21  3]
 [ 4  2  4  8 17]]
In [17]:
plt.rcParams["figure.figsize"]=(10,10)
metrics.ConfusionMatrixDisplay(confusion_matrix=metrics.confusion_matrix(y_test, y_pred_pca), display_labels=lfw.target_names).plot(cmap='YlGn', values_format='d')
plt.savefig('.\cmat2.jpg') 

速度は大幅に上がったけど、BushさんをPowelさんと間違って判断するケースが増えてしまいました。また、Bleairさんの特徴をうまく捉えられていないようです。

主成分を上位30個見てみましょう

In [25]:
nmax=30
n_comp = pca.components_.shape[0]
plt.rcParams["figure.figsize"]=(12,2*nmax/5+1)
for i in range(nmax):
    subplt = plt.subplot(nmax/5+1,5, i+1)
    subplt.imshow(pca.components_.reshape(n_comp,v,h)[i], cmap='gray')
plt.savefig('./pca.jpg')
plt.show()

PCAによってどの程度の情報が失われたのか、比較してみました。

  • 少しずつ情報が失われて画像の見た目としてばぼやけた感じに見えます。
  • 最初の画像は横顔ですが、特徴が完全に失われてしまっていますね。
In [24]:
plt.rcParams["figure.figsize"]=(8,6)
X_train_inv=pca.inverse_transform(X_train_pca)

for i in range(5):
    subplt = plt.subplot(2,5, i+1)
    subplt.imshow(X_train.reshape(n_train,v,h)[i], cmap='gray')
    
for i in range(5):
    subplt = plt.subplot(2,5, (i+1)+5)
    subplt.imshow(X_train_inv.reshape(n_train,v,h)[i], cmap='gray')
plt.savefig('./pca_loss.jpg')
plt.show()
In [20]:
plt.plot(pca.explained_variance_ratio_)
Out[20]:
[<matplotlib.lines.Line2D at 0x2a5e136c0b8>]

PCA累積寄与率の描画

In [21]:
plt.plot(np.cumsum(pca.explained_variance_ratio_),marker="o")
plt.xlim(0,n_comp)
plt.ylim(0,1.0)
plt.show()

1次元要素と2次元要素plotしてみた

In [22]:
for i in lfw.target_names:
    index =np.where(lfw.target_names[y_train]==i)
    plt.scatter(X_train_pca[index,0],X_train_pca[index,1],label=i,alpha=0.5)
plt.legend(loc=3)
plt.savefig('.\pca_2d.jpg') 
plt.show()

3次元要素まで含めてplotしてみた。う~む・・・

In [23]:
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)
for i in lfw.target_names:
    index =np.where(lfw.target_names[y_train]==i)
    ax.scatter(X_train_pca[index,0],X_train_pca[index,1],X_train_pca[index,2],label=i,alpha=0.5)
plt.legend(loc=3)
plt.savefig('.\pca_3d.jpg') 
plt.show()
In [ ]: