ユーニックス総合研究所

  • home
  • archives
  • python-janome-count-noun

PythonのJanomeで名詞の出現回数をカウントする【自然言語, 形態素解析】

Pythonで形態素解析

人間が自然発生的に使っている言語を「自然言語」と言います。
その自然言語を構造的に解析する手法の1つに「形態素解析(けいたいそかいせき)」というジャンルがあります。

自然言語に対して形態素解析を行うと、名詞や動詞を抽出したりできるようになります。

Pythonには形態素解析を行うライブラリに「Janome」があります。
Janomeは形態素解析器として有名な「MeCab」の辞書を使っており、精度的にはMeCabと同程度の解析が可能です。

MeCabのインストールは一手間かかる物でしたが、Janomeではこの手間が簡略化され、pipでインストールすればそのまま使うことが可能になっています。
ただし速度的にはCで書かれたMeCabの方が速いため、PythonのJanomeに対して速度と簡便さのトレードオフの関係になっています。
特に速度を必要としないのであればJanomeで問題はなさそうです。

Janomeのインストール

pipを使って↓のようにすればインストール可能です。

$ pip install janome  

Janomeでトークン列に分解

JanomeのtokenizerモジュールのTokenizerクラスを使うと自然言語を簡単に解析することができます。
Tokenizerクラスをインスタンス化して、メソッドtokenizeに自然言語が書かれたテキストを渡すと、Tokenizerは自然言語をトークン列に分解します。
各トークンはprintで出力することが可能です。

from janome.tokenizer import Tokenizer  

t = Tokenizer()  # トーカナイザー  
s = '本日は晴天なり'  # 解析対象の自然言語  

# 自然言語をトークン列に分解  
for tok in t.tokenize(s):  
    print(tok)  

出力結果。

本日    名詞,副詞可能,*,*,*,*,本日,ホンジツ,ホンジツ  
は      助詞,係助詞,*,*,*,*,は,ハ,ワ  
晴天    名詞,一般,*,*,*,*,晴天,セイテン,セイテン  
なり    助動詞,*,*,*,文語・ナリ,基本形,なり,ナリ,ナリ  

自力で名詞を抽出する

Tokenizer.tokenizeで生成されるトークンの型はjanome.tokenizer.Tokenです。

from janome.tokenizer import Tokenizer  

t = Tokenizer()  # トーカナイザー  
s = '本日は晴天なり'  # 自然言語  
toks = list(t.tokenize(s))  # トークン列に分解  
print(type(toks[0]))  # 最初のトークンのタイプは?  
<class 'janome.tokenizer.Token'>  

Tokenは属性にpart_of_speechを持っています。
このpart_of_speechにはトークンの持つ品詞がカンマ(,)区切りで並べられています。

from janome.tokenizer import Tokenizer  

t = Tokenizer()  # トーカナイザー  
s = '本日は晴天なり'  # 自然言語  

# トークン列に分解  
for tok in t.tokenize(s):  
    print(tok.part_of_speech)  # 品詞を出力  
名詞,副詞可能,*,*  
助詞,係助詞,*,*  
名詞,一般,*,*  
助動詞,*,*,*  

part_of_speechに「名詞」が含まれていればそのトークンは名詞に分類されているわけなので、これを調べることで単語が名詞かどうか判断できます。
↓のコードはpart_of_speechsplitで分解し、分解したリストに「名詞」が含まれていればトークンを出力します。

from janome.tokenizer import Tokenizer  

t = Tokenizer()  # トーカナイザー  
s = '本日は晴天なり'  # 自然言語  

# トークン列に分解  
for tok in t.tokenize(s):  
    pos = tok.part_of_speech.split(',')  # 品詞を分解  
    if '名詞' in pos:  # 品詞に「名詞」が含まれていれば  
        print(tok)  # トークンを出力  
本日    名詞,副詞可能,*,*,*,*,本日,ホンジツ,ホンジツ  
晴天    名詞,一般,*,*,*,*,晴天,セイテン,セイテン  

ちなみにトークンのsurfaceを参照すると、元の文字列で使われている形をそのまま取得できます。
readingでは読み、phoneticでは発音を参照できます。

from janome.tokenizer import Tokenizer  

t = Tokenizer()  
s = '本日は晴天なり'  

for tok in t.tokenize(s):  
    pos = tok.part_of_speech.split(',')  
    if '名詞' in pos:  
        print(tok.surface)  # 表層形を出力  
        print(tok.reading)  # 読みを出力  
        print(tok.phonetic)  # 発音を出力  
本日  
ホンジツ  
ホンジツ  
晴天  
セイテン  
セイテン  

自力で名詞の出現回数をカウントする

自力で名詞の出現回数をカウントするにはたとえば↓のようにします。
statという辞書を用意して、キーにトークンの表層形を使います。
トークンが名詞であればそのトークンの表層形のstatにカウントを追加します。

from janome.tokenizer import Tokenizer  

t = Tokenizer()  # トーカナイザー  
s = '猫が猫に話しかけると鳥が犬をくわえて逃げた'  # 自然言語  
stat = {}  # 統計用の辞書  

# トークン列に分解  
for tok in t.tokenize(s):  
    pos = tok.part_of_speech.split(',')  # 品詞を分解  
    if '名詞' in pos:  # 品詞に名詞が含まれていれば  
        if tok.surface in stat.keys():  # 統計にトークンの表層形が含まれていれば  
            stat[tok.surface] += 1  # カウントする  
        else:  
            stat[tok.surface] = 1  # 新規カウントする  

print(stat)  # 結果を出力  
{'猫': 2, '鳥': 1, '犬': 1}  

また、標準ライブラリのcollections.Counterを使えば↓のようにも書けます。

from janome.tokenizer import Tokenizer  
import collections  

t = Tokenizer()  # トーカナイザー  
s = '猫が猫に話しかけると鳥が犬をくわえて逃げた'  # 自然言語  
meisi = []  

# トークン列に分解  
for tok in t.tokenize(s):  
    pos = tok.part_of_speech.split(',')  # 品詞を分解  
    if '名詞' in pos:  # 品詞に名詞が含まれていれば  
        meisi.append(tok.surface)  # 名詞のトークンの表層形を保存  

c = collections.Counter(meisi)  # Counterで出現回数をカウント  

print(c)  # 結果を出力  
Counter({'猫': 2, '鳥': 1, '犬': 1})  

これはかなり原始的なコードです。
Janomeには名詞を抽出したり、単語をカウントするためのモジュールが備わっているため、これを使うと簡単に処理を書くことが出来ます。

Analyzerで名詞を抽出する

Janomeのanalyzer.Analyzerモジュールを使うと、簡単に名詞を抽出することができます。
Analyzerにはフィルターを指定することが出来ます。たとえば名詞のみのトークンを抽出したい場合は↓のようにPOSKeepFilterを指定します。
こうすることでトークン列の分解で名詞のみのトークンを抽出できます。

from janome.analyzer import Analyzer  
from janome.tokenfilter import POSKeepFilter  

# アナライザーのフィルター  
token_filters = [  
    POSKeepFilter(['名詞'])  # 名詞を抽出するようにする  
]  
analyzer = Analyzer(token_filters=token_filters)  # フィルターからアナライザーを生成  

s = '本日は晴天なり'  # 自然言語  

# トークン列に分解  
for tok in analyzer.analyze(s):  
    print(tok)  # トークンを出力  

Janomeで名詞の出現回数をカウントする

TokenCountFilterAnalyzerに指定すると、トークンの出現回数をカウントできます。
このフィルターとPOSKeepFilterを組み合わせれば、名詞のトークンの出現回数をカウントすることが可能です。
Analyzer.analyze()の結果をdictで辞書に変換すれば、カウント回数に対して単語のキーでアクセスできます。

from janome.analyzer import Analyzer  
from janome.tokenfilter import POSKeepFilter, TokenCountFilter  

# アナライザーのフィルター  
token_filters = [  
    POSKeepFilter(['名詞']),  # 名詞を抽出するようにする  
    TokenCountFilter(),  # トークンの出現回数をカウントする  
]  
analyzer = Analyzer(token_filters=token_filters)  # フィルターからアナライザーを生成  

s = '猫が猫に話しかけると鳥が犬をくわえて逃げた'  # 自然言語  

paris = analyzer.analyze(s)  # カウントする  
print(dict(paris))  # 結果を辞書に変換  

出力結果。

{'猫': 2, '鳥': 1, '犬': 1}  

問題

Q1: JanomeのTokenの品詞を参照したい。適当な属性を答えよ

  1. part_of_speech
  2. surface
  3. reading

Q2: Janomeで名詞を抽出したい。適当な処理を答えよ

  1. part_of_speechを参照して名詞のトークンを保存
  2. POSKeepFilterを使って名詞を抽出
  3. TokenCountFilterで名詞を抽出

Q3: Janomeで単語をカウントしたい。適当な処理を答えよ

  1. POSKeepFilterで単語をカウント
  2. TokenCountFilterで単語をカウント
  3. GreatSpeakerで単語をカウント

正解はこちら↓

Q1: 1
Q2: 1, 2
Q3: 2