私事ではありますが、2020年5月にコーギーという中型犬をお迎えしました。
愛犬のブログを運営してますので、見てもらえると嬉しいです。
「コーギー関連のツイートをwordcloudで可視化したい!」と思い立ち、以下の4項目を実施しました。
- TwitterAPIでツイートを取得
- 正規表現を用いてツイートを整形
- SudachiPyで形態素単位に分割 ← 今回
- WordCloudで可視化
今回は、「SudachiPyで形態素単位に分割」に関して説明していきます。
対象者
- SudachiPyの特徴を知りたい人
- SudachiPyでコードを書いてみたい人
SudachiPyの特徴
SudachiPyのメンテナーがこちらのリンクで書いてくれてます。
まとめると、特徴は以下の3つになります。
- small, core, fullの3タイプから、使用する辞書を選択できる
- 分割タイプも3タイプから選択できる
- 表記を正規化してくれる
##ざっくりとした要件定義
Input ... 前処理が完了した、DataFrame形式のツイートデータ
Output ... 単語の間をスペースで分割し、すべてのツイートを結合したstring
Inputは、こちらの記事で取得したデータフレーム(以下)になります。
Outputは、テキスト内容を形態素単位に分割し、次のようになります。
##コード
###コード全体
import pandas as pd
from sudachipy import tokenizer
from sudachipy import dictionary
class SudachiTokenizer():
def __init__(self, dict_type="core", mode="C", stopwords=None, include_pos=None):
if dict_type not in ["core", "small", "full"]:
raise Exception("invalid dict_type. 'core' ,'small' or 'full'")
self.tokenizer_obj = dictionary.Dictionary(dict_type=dict_type).create()
if mode not in ["A", "B", "C"]:
raise Exception("invalid mode. 'A' ,'B' or 'C'")
self.mode = getattr(tokenizer.Tokenizer.SplitMode, mode)
print(self.mode )
if stopwords is None:
self.stopwords = []
else:
self.stopwords = stopwords
if include_pos is None:
self.include_pos = ["名詞", "動詞", "形容詞"]
else:
self.include_pos = include_pos
def parser(self, text):
return self.tokenizer_obj.tokenize(text, self.mode)
def tokenize(self, text, pos=False):
res = []
for m in self.parser(text):
p = m.part_of_speech()
base = m.normalized_form() #.dictionary_form()
#print(base, ": ", p)
if p[0] in self.include_pos and base not in self.stopwords and p[1] != "数詞":
if pos:
res.append((base, p[0]))
else:
res.append(base)
return res
def create_word_chain(col, df, tokenizer):
word_lists=[]
for i in range(len(df)):
text = df.loc[i, col]
word_list = tokenizer.tokenize(text, pos=False)
for word in word_list:
word_lists.append(word)
word_chain =' '.join(word_lists)
return word_chain
include_pos = ["名詞", "動詞", "形容詞"]
stopwords = ["コーギー", "見る","為る", "今日","無い","居る","成る"]
sudachi_tokenizer = SudachiTokenizer(dict_type="core", mode="A", stopwords=stopwords, include_pos=include_pos)
word_chain = create_word_chain('TW_TEXT_mod', df, sudachi_tokenizer)
###コード解説
SudachiTokenizer()のinit
SudachiPyで必要なdict_typeとmodeを指定します。
SudachiPyの条件に合わない語句を指定した場合は、エラーが出るようにしています。
今回の分析では、dict_typeを変更しても、最終的な結果に大きな変化はありませんでした。(もしかすると、うまくdict_typeを変更できてないかもです。)
また、stopwords(形態素解析のあとに、削除するワード)とinclude_pos(形態素解析のあとに、含める品詞)を指定します。
class SudachiTokenizer():
def __init__(self, dict_type="core", mode="C", stopwords=None, include_pos=None):
if dict_type not in ["core", "small", "full"]:
raise Exception("invalid dict_type. 'core' ,'small' or 'full'")
self.tokenizer_obj = dictionary.Dictionary(dict_type=dict_type).create()
if mode not in ["A", "B", "C"]:
raise Exception("invalid mode. 'A' ,'B' or 'C'")
self.mode = getattr(tokenizer.Tokenizer.SplitMode, mode)
print(self.mode )
if stopwords is None:
self.stopwords = []
else:
self.stopwords = stopwords
if include_pos is None:
self.include_pos = ["名詞", "動詞", "形容詞"]
else:
self.include_pos = include_pos
#### SudachiTokenizerクラスのparserとtokenize関数
parser関数でparserを定義します。
結果はMorphemeのリストとなっており、表層形 (surface()) 、品詞 (part_of_speech()) 、読み (reading_form()) 、正規化した表現 (normalized_form()) を取得できます
(引用元:https://ohke.hateblo.jp/entry/2019/03/09/101500)
次に、tokenize関数で条件に合った語句を抽出し、リストに加えます。
今回は、正規化した表現で抽出したいので、normalized_form()を使用しています。
def parser(self, text):
return self.tokenizer_obj.tokenize(text, self.mode)
def tokenize(self, text, pos=False):
res = []
for m in self.parser(text):
p = m.part_of_speech()
base = m.normalized_form() #.dictionary_form()
#print(base, ": ", p)
if p[0] in self.include_pos and base not in self.stopwords and p[1] != "数詞":
if pos:
res.append((base, p[0]))
else:
res.append(base)
return res
####create_word_chain関数
次の章でwordcloudで頻出語を可視化しますので、語句と語句の間をスペースで区切り、ひとつのstringにします。
全てのtweetに対して実施する必要があるので、ツイートごとに先ほど作成した関数で形態素単位に分割し、for文でそれを全ツイート繰り返します。
def create_word_chain(col, df, tokenizer):
word_lists=[]
for i in range(len(df)):
text = df.loc[i, col]
word_list = tokenizer.tokenize(text, pos=False)
for word in word_list:
word_lists.append(word)
word_chain =' '.join(word_lists)
return word_chain
####作成した関数の実行
これまで作成した関数を実行し、word_chainを作成します。
最終結果に「居る」や「成る」といったコーギーの特徴を表さない語句が表示されていたので、これらの語句をstopwordsに追加しています。
次の章のwordcloudでもstopwordsを指定でき、そちらで指定したほうが全体の計算量が少ないかもしれません。。
(~~大変そうですし、~~今回は計算量は無視しました。)
include_pos = ["名詞", "動詞", "形容詞"]
stopwords = ["コーギー", "見る","為る", "今日","無い","居る","成る"]
sudachi_tokenizer = SudachiTokenizer(dict_type="core", mode="A", stopwords=stopwords, include_pos=include_pos)
word_chain = create_word_chain('TW_TEXT_mod', df, sudachi_tokenizer)
##まとめ
この記事では、形態素解析器を用いて、ツイートを形態素に分割しました。
次は、ついにwordcloudで可視化します。
こちらの記事で説明してますので、興味があれば見てもらえると嬉しいです。
##参考文献
日本語形態素解析器 SudachiPy の 現状と今後について
GitHub - WorksApplications/Sudachipy
形態素解析器比較 Sudachi vs Mecab+Neologd
Pythonで形態素解析器Sudachiを使う (SudachiPy)