python

【python】自然言語処理の方法【→プログラム初心者にもできる!】

11月 15, 2019

natural language processing on python
プログラム学生
自然言語処理ってどうやってやるんですか?
使う目的によっていろんな方法があるけど、今回は「文章中にでてくる単語の頻度と関係を調べる」という目的で、LDAというモデルを使った方法を説明するね。
Tommy

pythonで自然言語処理の方法の概要

summary of natural language processing

pythonでLDAというトピックモデルを使った自然言語処理の方法を説明します。

ここでは、指定した複数の文書(自然言語が並ぶ文章のこと)に対して、LDA分析を行い、LDAトピックモデル、辞書、コーパスを算出します。

また、LDAトピックモデルをWord Cloudという図を表示させ、文書中の単語の出現頻度を可視化します。

pythonで自然言語処理の方法の前提環境

environment of natural language processing

自然言語処理の方法の前提環境は、下の記事で説明している私の環境と同じ環境で確認しています。

オススメ
how to check version in python
【python】バージョン確認の方法【→プログラミング初心者向け】

続きを見る

また、レンタルサーバなどのLinuxサーバを使っている場合は、下の記事でプログラミングする環境の作り方を説明しています。

もし、まだプログラムする環境ができていない方は、先にこちらの記事を読んで、プログラミングできる環境をつくることをおすすめします。

オススメ
how to programming on rental server
レンタルサーバでプログラミングする方法【→ブログのサーバでできる!】

続きを見る

pythonで自然言語処理の方法のサンプルプログラム

sample program of natural language processing

このサンプルプログラムでは、複数の文書(自然言語が並ぶ文章)に対して、LDAトピックモデルをWord Cloudという図を表示させ、文書中の単語の出現頻度を可視化することを行います。

ライブラリのインポート

ここでは、全体の処理に必要なライブラリのインポートを行っています。

  • 形態素解析のツールであるtreetaggerのpythonラッパーのtreetaggerwrapper。
  • トピック分析を行う為のライブラリgensim。
  • 数値演算を行うライブラリnumpy
  • ワードクラウドという図を描画する為のライブラリwordcloud。
  • データをグラフにプロットする為のライブラリmatplotlib。
# Natural language processing
import treetaggerwrapper
import gensim
import numpy as np

# Wordcould
from wordcloud import WordCloud

#import matplotlib
import matplotlib.pylab as plt

LDA解析に使うパラメータを指定

次に、LDA解析に使うパラメータを指定します。

LDA_TOPIC_NUM:トピック数
MINIMUM_PROBABILITITY:所属確率の閾値(所属確率が0.001以上のトピックを返す)

#LDA parameter
LDA_TOPIC_NUM = 2
MINIMUM_PROBABILITITY = 0.001

treetaggerのインスタンスを取得する

次は、TreeTaggerのインスタンスを取得しています。

TreeTaggerは、ある英語の文章を単語とその品詞に分解してくれるツールです。

品詞の分類は下記のサイトの種類があります。

Tree Tagger Tags

この環境では、TreeTaggerのツールは「/usr/local/src/tree-tagger」のディレクトリに配置されているものとします。

def get_treetagger_instatnce():

	return treetaggerwrapper.TreeTagger(TAGLANG='en',TAGDIR='/usr/local/src/tree-tagger')

動詞と名詞だけ抽出

tagsで渡されるタグのリストを1つずつtagに格納しながら、名詞と動詞(Be動詞は除く)だけを選別しています。

最終的に戻り値docには、名詞と動詞のタグ(単語)がリストされていることになります。

def create_wordtaglist_1doc(tags):

	doc = []
	for tag in tags:

		# The case of Noun
		if tag.split()[1].startswith("N"):
			doc.append(tag.split()[2])

		# The case of Verb except for be verb
		elif tag.split()[1].startswith("V") and not tag.split()[1].startswith("VB"):
			doc.append(tag.split()[2])

	return doc

形態素に分解した配列を作成

doc_listの登録されている1つ1つの文章をdocに格納しながら、create_wordtaglist_1docから返却される1文書辺りの形態素解析結果のtagリストをdocsに保存しています。

なので、docsはリストを要素に持つリストなので、2次元のリストになります。

def create_morphological_docs(tagger,doc_list):
	docs = []
	for doc in doc_list:
		tags = tagger.TagText(doc)
		docs.append(create_wordtaglist_1doc(tags))
	return docs

辞書とコーパス作成

gensimライブラリのcorpora.Dictionaryをコールして、辞書を作成してdictionaryに格納しています。

その後、dictionary.doc2bowをコールして1docあたりのコーパスをリスト化してcorpusに格納しています。

def create_dic_and_corpus(docs):

	# create dictonary
	dictionary = gensim.corpora.Dictionary(docs)

	# create corpus
	corpus = [dictionary.doc2bow(doc) for doc in docs]

	return corpus,dictionary

LDAモデルの作成

def create_LDA_model(corpus,dictionary,topic_num):

	# LDA (Latent Dirichlet Allocation) processing
	tfidf = gensim.models.TfidfModel(corpus)
	corpus_tfidf = tfidf[corpus]
	lda = gensim.models.LdaModel(
							corpus=corpus_tfidf,
							id2word=dictionary,
							num_topics=topic_num,
							minimum_probability=MINIMUM_PROBABILITITY,
              )
	return lda

LDAモデルと辞書、コーパスの作成

create_morphological_docsでコーパスと辞書を作成します。

その後、先程求めたコーパスと辞書を元に、create_LDA_modelでLDAモデルを計算しています。

LDAモデル、辞書、コーパス、文書のリストを返却しています。

def make_lda_model(doc_list,topic_num):

	docs = create_morphological_docs(get_treetagger_instatnce(),doc_list)

	corpus,dictionary = create_dic_and_corpus(docs)

	lda = create_LDA_model(corpus=corpus,dictionary=dictionary,topic_num=topic_num)

	return lda,dictionary,corpus,docs

トピックモデルの画像作成

ここでは、トピックモデルをWord Cloudで描画しています。

トピックが4つよりも少ない場合は、1行のレイアウトでWord Cloudを表示し、4つ以上になると、数に応じて列を増やしています。

ちなみにWord Cloudの描画は、480*320のサイズで背景を黒に設定しています。

def make_topic_image(lda_model,corpus,dictionary):

	print('lda_model.num_topics : ' + str(lda_model.num_topics))

	if lda_model.num_topics < 4:
		fig, axs = plt.subplots(ncols=lda_model.num_topics, nrows=1,figsize=(15,7))
	else:
		fig, axs = plt.subplots(ncols=4, nrows=int(math.ceil((lda_model.num_topics+1)/4)),figsize=(15,7))

	axs = axs.flatten()

	for i, t in enumerate(range(lda_model.num_topics)):

		x = dict(lda_model.show_topic(t, 30))

		WC = WordCloud(
			width=480,
			height=320,
			background_color='black',
			max_words=2000,
			).fit_words(x)

		axs[i].imshow(WC)
		axs[i].axis('off')
		axs[i].set_title('Topic '+str(t))

	plt.tight_layout()
	plt.savefig('wordcloud/'+'best_topic_wordcould.png')
	plt.show()

自然言語処理一連の処理

doc_listに5つの文書(文章)をリスト形式で格納します。

これが分析対象のデータとなります。

その後、doc_listを引数にLDAモデルを作成する為にmake_lda_modelのメソッドをコールしています。これによってLDAモデル、辞書、コーパス、文書リストが得られます。

最後に、LDAモデルをWord Cloudという図で描写する為に、make_topic_imageのメソッドを呼び出します。

if __name__ == '__main__':

# Target doc list
	doc_list = [
				u'This is Tommy.',
				u'My name is Tommy.',
				u'It is python code.',
				u'Python is very cool.',
				u'You are a specialist.'
				]

	# Create lda dictionary corpus
	lda,dictionary,corpus,docs = make_lda_model(doc_list=doc_list,topic_num=LDA_TOPIC_NUM)
	print(lda)
	print(dictionary)
	print(corpus)

	# Making and showing topic image
	make_topic_image(lda_model=lda,corpus=corpus,dictionary=dictionary)

自然言語処理一連の処理結果

上記メイン関数での処理の結果、下記のような結果が得られました。

単語が5種類、トピック数が2、ディケイとチャンクサイズはデフォルトの値になっています。

Print文で、LDAモデル、辞書、コーパスを順に表示しているので、その結果が下記のようになります。

LdaModel(num_terms=5, num_topics=2, decay=0.5, chunksize=2000)
Dictionary(5 unique tokens: [u'python', u'specialist', u'code', u'name', u'Tommy'])
[[(0, 1)], [(0, 1), (1, 1)], [(2, 1), (3, 1)], [(2, 1)], [(4, 1)]]
lda_model.num_topics : 2

下の図がWord Cloudという図で単語の出現頻度を描写した結果です。

文書数が極端に少ないので、トピックのしての特徴があまりよく分かりませんが、名詞としての主旨としてトピックと、pythonのスペシャリストとしてのトピックの2つ分かれているような図になっているような気がします。

-python
-

© 2020 Tommy's blog Powered by AFFINGER5