はじめての手書き文字認識

スポンサーリンク
Python




今回は、機械学習を学び始めるなら、必ず通る道である「手書き文字認識」です。

手書き文字認識は、MNIST(Modified National Institute of Standards and Technology database)のデータセットで、scikit-learnや深層学習で使われるkeras、データ分析のコンペティションであるKaggleからデータを取り込むことができます。このデータセットは、0~9 の手書き数字の画像データセットです。

今までの、単純な行列のデータセット(分類:cancer、回帰:boston)ではないので、多少難しさを感じるかもしれませんが、その分面白みもあると思います。

今回はこの「手書き文字認識」について、簡単に説明していきます。解析はANACONDAからJupyter Labで行っていきます。

環境構築は以下の過去記事を参照してください。

M1 mac でanacondaをインストールし、Pythonを動作確認
M1 mac miniを購入したので、anacondaのインストールし、Pythonの動作を確認しました。 以前はWindowsでのanacondaのインストール方法を提示しました。 macでのイ...
【2021年最新】WindowsでAnacondaをインストールする方法、初心者がPythonの環境を構築する
Pythonの環境構築におすすめなのが、「anaconda」です。anacondaのなかにある、Jupyter Labはデータ解析や機械学習に非常に相性がいいです。理由は、コードを実行すると結果を返してくれます。その結果をみて、新たなコード

必要なライブラリ―をインポート

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib import pyplot
import seaborn as sns
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')

データセットを取り込む

from sklearn.datasets import fetch_openml
mnist=fetch_openml('mnist_784',version=1)
X,y=mnist["data"],mnist["target"]

データの行列の数を確認してみましょう

X.shape

出力:
(70000, 784)

これは、行数(手書き文字の数)が7万、列数(説明変数の数)が 784 あるということを表しています。説明変数の数は文字の認識なので、ピクセルで表しています。つまり、28✕28の画像で文字を認識しています。28✕28=784 説明変数の数と同じですね。

y.shape

出力:
(70000,)

これは、目的変数の行数が7万あるということを表しています。

どのようなデータか確認してみましょう

some_digit=X[0]    # mnistデータの1番目を指定する
some_digit_image=some_digit.reshape(28,28)
plt.imshow(some_digit_image,cmap="binary")
plt.axis("off")
plt.show()

出力:

ひとつのデータをみてみると、手書きの「5」にみえます。
これを28✕28のピクセルでみると、

こんなデータになっています。28行、28列のピクセル(ドット)で、手書き文字の色が濃い(黒い)場所は数値が大きいです。
ではこの手書き文字の正解を確認してみましょう。

y[0]      # mnistデータの1番目のラベル(答え)を確認する

出力:
‘5’

やはり、「5」でしたね。
次に、目的変数である、正解のラベルがどれくらいの分布かを確認してみましょう。

sns.countplot(np.sort(y))

出力:

0~9まで、だいたい7000個前後で、大きな差はないですね。(個数に偏りがあると、面倒な解析を加えるため、確認する必要がある)

機械学習がしやすいデータの形に整える

# データを訓練用とテスト用に分割する
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size = 0.2,
    random_state = 1,
    stratify = y)

データの個数を確認しておきましょう。

print('訓練用説明変数 :',X_train.shape)
print('訓練用目的変数 :',y_train.shape)
print('テスト用説明変数:',X_train.shape)
print('テスト用目的変数:',y_test.shape)

出力:
訓練用説明変数 : (56000, 784)
訓練用目的変数 : (56000,)
テスト用説明変数: (56000, 784)
テスト用目的変数: (14000,)

最近傍法(kNN法)で学習する

from sklearn.neighbors import KNeighborsClassifier

knn_clf = KNeighborsClassifier(n_neighbors=3,n_jobs=-1)
knn_clf.fit(X_train, y_train)

これだけで、機械学習(最近傍法)は終わり。
非常に簡単なコードですね。結果を確認してみましょう。

モデルの評価(最近傍法)

from sklearn.metrics import accuracy_score

y_pred = knn_clf.predict(X_test)
accuracy_score(y_test, y_pred)

出力:
0.9723571428571428

訓練に使用していないテストデータで、正解率97.2%でした。

初心者のための回帰問題の評価指標

悪くない結果です。
今回使用した手書き文字認識は、最近傍法との相性がいいです。これ以上の正解率は深層学習を使ったほうがいいでしょうね。
もう少し、詳細に確認していきましょう。

from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
print("Classification report for classifier %s:\n%s\n"
      % (knn_clf, classification_report(y_test, y_pred)))
print("Confusion matrix:\n%s" % confusion_matrix(y_test, y_pred))

出力:

もう少し、見やすくしてみましょう。

def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    if normalize:
        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]

    thresh = cm.max() / 2.
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            plt.text(j, i, cm[i, j],
                     horizontalalignment="center",
                     color="white" if cm[i, j] > thresh else "black")

    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')

plot_confusion_matrix(confusion_matrix(y_test, y_pred), range(10))

出力:

縦(True label)が正解値、横(Predicted label)が予測値です。

手書き文字認識も0~9までのクラス分類です。モデルの評価はこちらを参照してください。

これで、手書き文字の機械学習とその評価が終了しました。
今回は非常に簡単に、さまざまな過程を飛ばしていますが、結果は悪くないと思います。
労力対効果を考慮することも大切ですね。





コメント

タイトルとURLをコピーしました