Pythonの機械学習入門(2)~言語の種類をNaive Bayesで判定

Pythonの機械学習ライブラリ「scikit-learn」の使い方を簡単に説明します。今回は機械学習を用いて言語の種類を判定(分類)します。

テキストデータの入手

先ずは、機械学習で使用するテキストデータを入手します。今回はWikipediaで動物名を検索し、文章をコピーして、テキストファイルに貼り付けて保存しました。

text data

フォルダ名 ファイル名
train Eng_dog.txt  Eng_cat.txt  Eng_bird.txt
Deu_dog.txt  Deu_cat.txt  Deu_bird.txt
Esp_dog.txt  Esp_cat.txt  Esp_bird.txt
test Eng_cattle.txt  Deu_cattle.txt  Esp_cattle.txt
trial sheep.txt

dataフォルダ内に、train(学習用)、test(テスト用)、trial(未知のデータ)のサブフォルダを作成し、各サブフォルダ内に各言語のテキストファイルを置きます。

ファイル名は「言語名_動物名.txt」とします。言語は英語(Eng)、ドイツ語(Deu)、スペイン語(Esp)の3種類です。

テキストデータの分量は、1つのファイルが50KB以上になるように文章を用意しました。

テキストデータの分量が少ない場合、言語を正しく判定することができない可能性もあります。

学習データの読込み

# 学習データの準備
X_train = []
y_train = []
for file in glob.glob('./data/train/*.txt'):
    y_train.append(file[13:16])
    text = ''
    for line in open(file, 'r'):
        text = text + line
    X_train.append(getCodePoint(text))

複数のファイルを読込むのにglobを使用しました。dataフォルダ内のtrainフォルダにあるテキストファイルをそれぞれ読込み、1ファイルずつ処理していきます。

特徴量データと教師データに分離

データを特徴量データと教師データに分離します。X_trainは特徴量データで、y_trainは教師データです。

教師データには言語の種類(ファイル名の頭文字3文字)を入力します。y_trainは9×1の一次元のベクトルとなります。

具体的には、[‘Deu’, ‘Deu’, ‘Deu’, ‘Eng’, ‘Eng’, ‘Eng’, ‘Esp’, ‘Esp’, ‘Esp’]のようなデータになります。

特徴量データには、Unicodeのコードポイントの出現頻度を入力します。これは文章中に現れる文字をコードポイントに変換して、出現回数をカウントしたものです。

コードポイントの出現頻度は、65535(16bit)個の要素を持つ一次元のベクトルとなります。また、X_trainは9×65535の行列データとなります。

Unicodeのコードポイント

Unicodeのコードポイントの出現頻度を算出する関数getCodePointは以下の通りです。

# Unicodeのコードポイント変換
def getCodePoint(text):
    vec = np.zeros(MAX_VALUE)  
    for i in range(len(text)):
        code_point = ord(text[i])

        if code_point <= MAX_VALUE:
            vec[code_point] += 1

    vec = vec / len(text)
    return vec

先ず、Unicodeのコードポイントをカウントするために65535個の要素を持つ一次元のベクトルを用意します。

入力されたテキストデータを、一文字ずつUnicodeのコードポイントに変換し、出現回数をカウントしていきます。

最後に、テキストデータの長さで割って正規化しています。このベクトルが特徴量データとなります。

以降では、このUnicodeのコードポイントの出現頻度(つまり、よく使用される文字の種類)に応じて、言語を判定することになります。

テストデータの読込み

# テストデータの準備
X_test = []
y_test = []
for file in glob.glob('./data/test/*.txt'):
    y_test.append(file[12:15])
    text = ''
    for line in open(file, 'r'):
        text = text + line
    X_test.append(getCodePoint(text))

学習データと同様に、テストデータを読込みます。dataフォルダ内のtestフォルダに入っているテキストファイルをそれぞれ読込みます。

モデルの学習

# モデルの学習
estimator = GaussianNB()
estimator.fit(X_train, y_train)

今回は言語の種類を判定(分類)するために、ナイーブベイズの学習アルゴリズムを使用しました。

機械学習の分類のアルゴリズムはいくつかあり、データ数やデータの特性に応じて最適なものを選択する必要があります。

先ずは、GaussianNBメソッドでアルゴリズムをestimatorに設定します。次にfitメソッドにて学習データセット(X_trainとy_train)を与えて学習させます。

これで、学習済みの「モデル」(または「学習器」)が完成しました。以降は、このモデルを用いて性能を評価したり、未知のデータに対する判定を行います。

モデルの性能評価

# モデルの評価
y_pred = estimator.predict(X_test)
print ("予測ラベル = ", y_pred)
print ("正解ラベル = ", y_pred)
print ("正解率 = ", accuracy_score(y_test, y_pred))

ここで、学習済みのモデルの性能を評価します。新しいデータセットに対して、言語の種類をどれだけ正しく分類できるかを確認します。

predictメソッドにて特徴量のテストデータを与えて、予測した言語の種類をy_predに保存します。

そして、accuracy_scoreメソッドでy_predと、実際の言語の種類y_testの正解率を算出します。値は0~1で、1は100%合致していたことを意味します。

実行すると、正解率は1になると思います。言語を正しく分類することに成功しました。

accuracy_score

未知のテキストデータの判定

# 未知のデータの分類
X_trial = []
text = ''

for line in open('./data/trial/sheep.txt', 'r'):
    text = text + line
X_trial.append(getCodePoint(text))

y_pred = estimator.predict(X_trial)
print ("予測ラベル =", y_pred)

上手く学習できたモデルを使って、実際に未知のテキストデータを判定してみましょう。

dataフォルダ内のtrialフォルダに入っているファイル(sheep.txt)を読込みます。このテキストデータは任意の言語のものとします。

このテキストデータより特徴量データX_trialを作成します。そして、predictメソッドにて未知のテキストデータに対して、言語の種類の判定を実行しました。

predict_unkown

実行結果は、英語(Eng)、ドイツ語(Deu)、スペイン語(Esp)の何れかのラベルが表示されます。入力した言語が正しく表示されたと思います。

もし、間違った結果が表示された場合は、学習させるテキストデータや、未知のテキストデータの分量を増やしたり、テキストデータの中身の文章を多様化させる必要があります。

まとめ

今回はPythonの機械学習ライブラリ「scikit-learn」を使用して、言語の種類を判定するモデルを作成しました。押さえておきたいポイントとしては、

  • Webで公開されている一般的なテキストデータを学習に使用した
  • 特徴量データとして、Unicodeのコードポイントの頻度情報を使用した
  • 学習済みのモデルを使って、「未知のテキストデータ」に対して言語の判定を実行した

参考文献

すぐに使える! 業務で実践できる! Pythonによる AI・機械学習・深層学習アプリのつくり方
ソシム (2018/6/29)