筋トレ大学生によるアウトプット雑記

筋トレや読書のことをはじめとして、プログラミングその他日常生活における様々なことについて書いていきます。

SVMを用いた教師あり機械学習の実装方法!【語義判別】

スポンサーリンク

f:id:daimori1005:20191010122358p:plain

こんにちは!

今日も研究の合間を縫ってブログを書いていこうと思います。



今回は、自然言語処理について。

PythonでSVMを用いた教師あり機械学習の手法を記していきます。



機械学習を始めてみたい方にとって、サンプルプログラムを動かしているだけでは楽しくないですし、成長も感じられないと思います。



そんな皆さんに、簡単かつそこそこ本格的な機械学習を行う方法を伝授したいと思います。

基本的な事項も記していきますので、この記事だけで機械学習の実装部分はコンプリートできますよ。



そもそも自然言語処理ってなに?という方はこちら。
www.i-like-output.work


自然言語処理における、機械学習を使って分類問題を解く方法は以下のようになります。

データを準備 → 前処理を行う → データセット構築 → 機械学習部分の実装 → 学習 → テスト

順を追って解説していきます。

今回は、語義判別(語義曖昧性解消)を行っていきたいと思います。
なにそれ?という方はこちらをご覧ください。
www.i-like-output.work


また、併せて文書分類に応用する場合の注意点も書いていきます。

f:id:daimori1005:20191010145510j:plain

スポンサーリンク


データの準備

まずは、データの準備をします。
手に入る方はコーパスを使うと早く大量にデータを得ることができます。
手に入らない方は、自分の手で構築するか、インターネットで探してくる必要があります。

今回は簡単のため、10文程度でやっていきます。
曖昧性を解消する単語は "学習" でやっていきます。

学習の意味は、

  1. 学校で学ぶ
  2. 努力することにより、学問や知識、技術を身に着ける

の2つを考えていきます。

文章は以下。

文章例

日本語 は 特殊 と しりごみ せ ず 、 世界 の 日本語 学習:2 熱 に 積極的 に こたえ て い き た い 。

入力 装置 を 含め て 子供 向け の 端末 の 基準 は あ り ませ ん し 、 学習:1 ソフト の 互換性 、 パソコン の 互換性 も な い の が 現状 です 。

美術 は 算数 や 国語 の よう に 、 一定 の 到達 度 に 向か っ て 学習:2 する もの で は な い 。

筆者 の 癖 の 学習:2 に よ る 筆者 認識 の 技術 は , 手書き文字認識 の 性能 向上 の ため に 使 う こと が でき る が , この よう な 立場 から の 研究 は まだ ほとんど な さ れ て い な い .

歴史 で 平安時代 に つ い て 学習:1 し て から 、 わたし は 、 清少納言 と い う 女性 に 興味 を 抱 く よう に な っ た 。

本書 は 米国 国防総省 が 開発 し た 高級 プログラミング 言語 Ada の 初心 者 向け の 解説 、 学習:2 書 で あ る 。

勉強 会 で は 今 、 基礎的 な 学習:2 の 段階 を 終え 、 質問 作り の 段階 に 入 っ て い る 。

日ごろ 学習:1 し て い た 北京語 と は まったく ちが う 方言 で あ る 。

入学 以来 、 実施 さ れ て き た 学習:1 会 を 、 なぜ 今回 、 2 年 生 だけ が 問題 に する の か 。

例えば 学校 で は 母国語 の 学習:1 が 単位 と し て 認め られ る 。

学習という単語には、コロンを付け、その後にクラスを書いています。
このように、対象の単語にはクラスを同時に張り付けておくと後々楽になります。
文書分類の場合は、実装部分で紹介しますが、あらかじめカテゴリのクラスを保存しておくのが良いと思います。

また、こちらの文章はすでに分かち書きをしてあります。
データを自作する人は、分かち書きはMeCabを使うと良いと思います。

import MeCab
m = MeCab.Tagger("-Owakati")

wakati = m.parse("文章")

というようにするとわかち書きできます。

MeCabの使い方をこちらにまとめました!
www.i-like-output.work


データの前処理

前処理手順としては、

分かち書き → 不要な情報の削除 → (活用を変える)

となります。

分かち書き

分かち書きについては、上記のようにMeCabにかけるだけで終わります。

不要な情報の削除

ここでは、文章に影響を与えないような単語を削除します。

例えば、記号や、一文字のひらがな単語、一文字の数字などです。

これらの余分な情報を削除することで、単語の意味を取り出すときにより正確になります。
余分な情報を削除することが、有効であると証明する論文も存在します。

ただし、短い文章の場合は、単語数が少なくなり逆の効果をもたらす場合もあるので注意しましょう。

例の文章を削除してみると、以下のようになります。

文章例

日本語 特殊 しりごみ 世界 日本語 学習:2 熱 積極的 こたえ

入力 装置 含め 子供 向け 端末 基準 ませ 学習:1 ソフト 互換性 パソコン 互換性 現状 です

美術 算数 国語 よう 一定 到達 度 向か 学習:2 する もの

筆者 癖 学習:2 筆者 認識 技術 手書き文字認識 性能 向上 ため 使 こと でき この よう 立場 から 研究 まだ ほとんど

歴史 平安時代 学習:1から わたし 清少納言 女性 興味 抱 よう

本書 米国 国防総省 開発 高級 プログラミング 言語 Ada 初心 者 向け 解説 学習:2 書

勉強 会 今 基礎的 学習:2 段階 終え 質問 作り 段階 入

日ごろ 学習:1 北京語 まったく ちが 方言

入学 以来 実施 学習:1 会 なぜ 今回 年 生 だけ 問題 する

例えば 学校 母国語 学習:1 単位 認め られ

このように重要度合いの高い単語だけを取り出すことができます。

ちなみに、この不要な情報を削除するアルゴリズムは自作です。

活用を変える

こちらは、原形に戻すなどの操作を行います。

やらなくてもやってもどちらでもよいと思います。

原形に戻すのも、MeCabで行えます。

データセット構築

データセットを構築しましょう。

今回は、"学習"の前後5単語を取り出してきて、分散表現の平均を取りたいと思います。

import numpy

#分散表現用の辞書を作る
with open('training.model', 'r') as f:
    ss = f.readline().split()
    n_vocab, n_units = int(ss[0]), int(ss[1])
    word2index = {}
    index2word = {}
    w = numpy.empty((n_vocab, n_units), dtype=numpy.float32)
    for i,line in enumerate(f):
        ss = line.split()
        assert len(ss) == n_units + 1
        word = ss[0]
        word2index[word] = i
        index2word[i] = word
        w[i] = numpy.array([float(s) for s in ss[1:]], dtype=numpy.float32)


target = "学習"
X = [None] * 10#ベクトルを入れる配列
Y = [None] * 10#ラベルを入れる配列

with open(filename,'r') as f:
    for i,line in enumerate(f):
        word = line.rstrip().split()
        target_index = [i for i,x in enumerate(word) if target in x][0]#対象単語のインデックスを取得
        label = word[target_index].split(":")[1]
        
        
        word_list = [word[i] for i,x in enumerate(word) if target_index-5 <= i <= target_index+5 and i != target_index]#前後5単語取得

        sum_vec = numpy.zeros(200, dtype=numpy.float32)#初期化
        ave_vec = numpy.empty(200, dtype=numpy.float32)
        count = 0#ベクトルがなかった場合に使う

        for x in word_list:
            if x not in word2index:
                count+=1
                continue
            sum_vec += w[word2index[x]]
        ave_vec = sum_vec / (len(word_list) - count)
        
        X[i] = ave_vec
        Y[i] = label

numpy.save(
    "example-x",
    X
)
numpy.save(
    "example-y",
    Y
)

こんな感じ。

最後にnumpy形式で配列を保存します。

filenameのところは、文章を保存しておいたファイルの名前に変えてください。

このような感じでプログラムを書けば、ベクトル平均を取り出せます。

文書分類などでは、文章全体をベクトル化します。
そして、文章ごとの特徴を抜き出して、カテゴリに分類します。
なのでその場合は、単語を取り出す範囲を変えて実行してください。

SVMの実装

今回は線形カーネルを使います。

SVMはすぐに実装できます。

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report

X = np.load(file="example-x.npy")
Y = np.load(file="example-y.npy")

x_train, x_test, y_train, y_test = train_test_split(X, Y, train_size=0.6)

svm = LinearSVC(C=1)
svm.fit(x_train,y_train)
pred = svm.predict(x_test)
acc = accuracy_score(pred,y_test)
print("ACC",acc)

たったこれだけです。

学習とテスト

上記のコードを実行すれば、学習とテストも同時に行われます。

結果は毎回変わりますが、今回はデータが少ないのでうまく学習できていないですね。

使うデータを増やすことで、もっと精度を上げることができます。

これで、教師あり機械学習は終わりです。

まとめ

いかがでしたか?

今回は、SVMを用いた実践的な分類問題を解く方法を記事にしました。

機械学習は最近注目されている技術なので、触ってみたい方も多数いらっしゃると思います。
この記事を読んで、さらに機械学習に興味を持つ人が増えたらうれしい限りですね。

それでは!

スポンサーリンク