PythonはAIや機械学習領域のライブラリを豊富に持っており、近年非常に高い人気を誇っています。今回はPythonを使用して自然言語(人間が読み書きする言語)を処理する方法ご紹介します。
近年、自然言語処理の領域は急速に発展しており、機械翻訳(英語から日本語の翻訳等)の精度も年々向上しています。今回はその自然言語処理の基礎の基礎の部分をお伝えし、Pythonで処理する方法をご紹介いたします。
株式会社メンバーズ メンバーズデータアドベンチャー データアナリスト
メンバーズに新卒入社後大手企業のWEBサイト運用やアクセス解析等に従事。メンバーズデータアドベンチャーに異動し、クライアント企業にデータアナリストとして常駐。
自然言語とは?
自然言語とは人間が日常的に読み書きする、所謂普通の言語のことを指します。これと対比されるのが機械語やプログラミング言語で、Pythonなどが該当します。人間が扱う言語と機械が扱う言語を区別するために「自然」言語という用語を使用しています。その自然言語を扱う技術が自然言語処理です。
自然言語処理の流れ
自然言語処理は人間が普段使用している言語をプログラムで扱えるようにする技術です。従って、自然言語をプログラムで扱える形に変換する必要があり、その手法として次のような方法がよく用いられます。まず形態素解析と呼ばれる作業で文章を形態素の単位に分割します。その分割された文章を様々の方法でベクトル(数値の並び)に変換します。本記事ではこの流れで実施する自然言語処理の一例をご紹介します。(ベクトルに変換する以外にも大規模な言語データ用いて構文解析や係り受け解析などを実施する場合もあります。)
形態素解析
形態素とは「意味を持つ言語の最小単位」のことを指します。つまり、形態素解析とはこれ以上分割すると意味をなさない語になってしまうまで文章を分割することです。実際にPythonを使用して形態素解析を実施してみます。今回形態素解析器にはmecabを使用します。(形態解析器にはいくつか種類がありますがmecabは特に処理が高速のため、よく用いられています。)
今回はPythonでmecabを扱うにあたって「mecab-python3」というライブラリを使用します。Python3.6以上のバージョンで動作するライブラリになるので、Python3.6以上の環境で下記コマンドを実行してライブラリをインストールしてください。
pip install mecab-python3
=コマンド====
形態素解析を実施するに当たっては裏側で辞書を持っている必要があります。今回はUnidicという辞書を使用するために、下記コマンドで辞書をインストールします。
pip install unidic-lite
==========
これで形態素解析を実施する準備が整いました。それでは「私は猫が大好きです」という文章を形態素の単位で分割してみようと思います。
Pythonで下記を実行します。
import MeCab
wakati=MeCab.Tagger(“-Owakati”)
sentence_wakati = wakati.parse(“私は猫が好きです”).split()
print(sentence_wakati)
==============
[‘私’, ‘は’, ‘猫’, ‘が’, ‘好き’, ‘です’]
=============
「私は猫が大好きです」という文章が「私 / は / 猫 / が / 大好き /です」に分割されました。この1つ1つが形態素と呼ばれる単位になっています。日本語は英語のように単語と単語の間がスペースで分かれていないので、形態素解析器使用した分割処理が必要になります。
文章をベクトル化する
それでは文章をベクトル化してプログラムで処理できるかたちに変換してみましょう。ベクトル化する技術には様々な方法がありますが、今回は最も基本的なBag of Wordsという手法をご紹介します。
Baf of Words
下記のような4つ文章がある状態を考えます。
- A:私は猫が好きです
- B:私は猫が嫌いです
- C:私は犬が好きです
- D:私は犬が嫌いです
これらの文章をそれぞれ形態素に分解します。
import MeCab
wakati=MeCab.Tagger(“-Owakati”)
sentence_list = [“私は猫が好きです”, “私は猫が嫌いです”, “私は犬が好きです”, “私は犬が嫌いです”]
sentence_wakati_list = [wakati.parse(i).split() for i in sentence_list]
print(sentence_wakati_list)
==============
[[‘私’, ‘は’, ‘猫’, ‘が’, ‘好き’, ‘です’],[‘私’, ‘は’, ‘猫’, ‘が’, ‘嫌い’, ‘です’],[‘私’, ‘は’, ‘犬’, ‘が’, ‘好き’, ‘です’],[‘私’, ‘は’, ‘犬’, ‘が’, ‘嫌い’, ‘です’]]
==============
形態素に分解すると下記のようになりました。
- A:私 / は / 猫 / が / 好き / です
- B:私 / は / 猫 / が / 嫌い / です
- C:私 / は / 犬 / が / 好き / です
- D:私 / は / 犬 / が / 嫌い / です
ここでそれぞれの文章の中身を注目してみると、「私」「は」「猫」「犬」「が」「好き」「嫌い」「です」という8つの形態素で構成されていることがわかります。
縦軸に文章、横軸にそれぞれの文の中にどの形態素が含まれているかを「0」又は「1」でフラグ付けしたマトリクスになります。
これが最も簡単なBag of Wordsの形です。Pythonでは下記を実行することでBag of Wordsを作成することができます。(直接Bag of Wordsを作成するライブラリもありますが、今回は仕組みをわかりやすくするためにNumpyのみを使用してBag of Wordsを作成しています。)
import numpy as npword_to_index = {}
index_to_word = {}
for s in sentence_wakati_list:
for w in s:
if w not in word_to_index:
new_index = len(word_to_index)
word_to_index[w] = new_index
index_to_word[new_index] = w
corpus = np.zeros((len(sentence_wakati_list), len(word_to_index)))
for i, s in enumerate(sentence_wakati_list):
for w in s:
corpus[i, word_to_index[w]] = 1
==============
Bag of Wordsでできること
Bag of Wordsを作成したことで、文章をベクトルに変換することができました。ベクトルに変換することでプログラム上での処理が可能になります。例えば文章間の類似度を定量的に計算することができます。
- A:私は猫が好きです
- B:私は猫が嫌いです
- C:私は犬が好きです
- D:私は犬が嫌いです
再度上記の文章を例に「AとB」の類似度「AとC」の類似度「AとD」の類似度を計算します。(類似度の計算にはcos類似度という方法を使用しています)
def cos_sim(x, y):
return np.dot(x, y) / (np.sqrt(np.sum(x**2)) * np.sqrt(np.sum(y**2)))for i, v in enumerate([“B”, “C”, “D”]):
per = cos_sim(corpus[0], corpus[i + 1])
print(v + “:” + f”{per:.2}”)
==============
B:0.83
C:0.83
D:0.67
==============
- AとBの類似度:0.83
- AとCの類似度:0.83
- AとDの類似度:0.66
という結果になりました。文章をみてもわかるように「AとB」「AとC」は異なる単語が1つだけですが、「AとD」は異なる単語が2つ存在しています。従って「AとD」が一番類似度が低いという結果になっています。このように文章をベクトル化することで定量的に文章の類似度を計算することができます。
おわりに
本記事では自然言語処理の基礎の基礎についてご紹介しましたが、昨今この領域は急速に発展しています。特に自然言語処理において重要とされているのは、文章の情報を如何に保持させたままベクトルに落とし込むか、という点です。今回は最も簡単なBag of Wordsという手法を紹介しましたが、単語の語順や単語の多義性、文脈まで考慮してベクトルに落とし込む技術も登場しています。本記事を読んで自然言語処理に興味を持たれた方は是非、色々と調べていただければと思います。本記事を最後まで読んでいただきありがとうございました。