아마추어 언어 처리 100 개 노크 : 37

언어 처리 100개 노크 2015의 도전 기록입니다. 환경은 Ubuntu 16.04 LTS + Python 3.5.2::Anaconda 4.1.1 (64-bit)입니다. 과거 노크 목록은 여기에서 확인하십시오.

제4장: 형태소 해석



나츠메 소세키의 소설 「고배는 고양이이다」의 문장(neko.txt)을 MeCab를 사용해 형태소 해석해, 그 결과를 neko.txt.mecab라는 파일에 보존하라. 이 파일을 사용하여 다음 질문에 해당하는 프로그램을 구현하십시오.

문제 37, 38, 39는 matplotlib 또는 Gnuplot을 사용할 수 있습니다.

37. 빈도 상위 10어



출현 빈도가 높은 10어와 그 출현 빈도를 그래프(예를 들면 막대 그래프 등)로 표시하라.

완성된 코드:



main.py
# coding: utf-8
import MeCab
from collections import Counter
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

fname = 'neko.txt'
fname_parsed = 'neko.txt.mecab'


def parse_neko():
    '''「吾輩は猫である」を形態素解析
    「吾輩は猫である」(neko.txt)を形態素解析してneko.txt.mecabに保存する
    '''

    with open(fname) as data_file, \
            open(fname_parsed, mode='w') as out_file:

        mecab = MeCab.Tagger()
        out_file.write(mecab.parse(data_file.read()))


def neco_lines():
    '''「吾輩は猫である」の形態素解析結果のジェネレータ
    「吾輩は猫である」の形態素解析結果を順次読み込んで、各形態素を
    ・表層形(surface)
    ・基本形(base)
    ・品詞(pos)
    ・品詞細分類1(pos1)
    の4つをキーとする辞書に格納し、1文ずつ、この辞書のリストとして返す

    戻り値:
    1文の各形態素を辞書化したリスト
    '''
    with open(fname_parsed) as file_parsed:

        morphemes = []
        for line in file_parsed:

            # 表層形はtab区切り、それ以外は','区切りでバラす
            cols = line.split('\t')
            if(len(cols) < 2):
                raise StopIteration     # 区切りがなければ終了
            res_cols = cols[1].split(',')

            # 辞書作成、リストに追加
            morpheme = {
                'surface': cols[0],
                'base': res_cols[6],
                'pos': res_cols[0],
                'pos1': res_cols[1]
            }
            morphemes.append(morpheme)

            # 品詞細分類1が'句点'なら文の終わりと判定
            if res_cols[1] == '句点':
                yield morphemes
                morphemes = []


# 形態素解析
parse_neko()

# Counterオブジェクトに単語をセット
word_counter = Counter()
for line in neco_lines():
    word_counter.update([morpheme['surface'] for morpheme in line])

# 頻度上位10語の取得
size = 10
list_word = word_counter.most_common(size)
print(list_word)

# 単語(x軸用)と出現数(y軸用)のリストに分解
list_zipped = list(zip(*list_word))
words = list_zipped[0]
counts = list_zipped[1]

# グラフで使うフォント情報(デフォルトのままでは日本語が表示できない)
fp = FontProperties(
    fname='/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf'
)

# 棒グラフのデータ指定
plt.bar(
    range(0, size),     # x軸の値(0,1,2...9)
    counts,             # それに対応するy軸の値
    align='center'      # x軸における棒グラフの表示位置
)

# x軸のラベルの指定
plt.xticks(
    range(0, size),     # x軸の値(0,1,2...9)
    words,              # それに対応するラベル
    fontproperties=fp   # 使うフォント情報
)

# x軸の値の範囲の調整
plt.xlim(
    xmin=-1, xmax=size  # -1〜10(左右に1の余裕を持たせて見栄え良く)
)

# グラフのタイトル、ラベル指定
plt.title(
    '37. 頻度上位10語',    # タイトル
    fontproperties=fp   # 使うフォント情報
)
plt.xlabel(
    '出現頻度が高い10語',# x軸ラベル
    fontproperties=fp   # 使うフォント情報
)
plt.ylabel(
    '出現頻度',         # y軸ラベル
    fontproperties=fp   # 使うフォント情報
)

# グリッドを表示
plt.grid(axis='y')

# 表示
plt.show()

실행 결과:



터미널
[('の', 9198), ('。', 7486), ('て', 6798), ('、', 6772), ('は', 6418), ('に', 6177), ('を', 6047), ('と', 5486), ('が', 5339), ('た', 3968)]



matplotlib 설치



문제로 권장되는 matplotlib은 이미 들어있었습니다. 이슈02에 넣은 Anaconda에 포함되어있는 것 같습니다. 좋았어요^^

matplotlib 사용법


parse_neko(), neco_lines()word_counter를 찾는 곳은 전문과 동일합니다.

matplotlib 그 자체에 대해서는, 넷에 해설이 많이 있기 때문에 자세한 것은 할애합니다. 공식 사이트는 여기입니다.

다음은 몇 가지 포인트입니다. 코드에도 많게 코멘트를 넣어 보았습니다.

처음 실행했을 때의 warning



matplotlib를 처음import하면 다음과 유사한 경고가 표시됩니다.

터미널
segavvy@ubuntu:~/ドキュメント/言語処理100本ノック2015/37$ python main.py 
/home/segavvy/anaconda3/lib/python3.5/site-packages/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment.
  warnings.warn('Matplotlib is building the font cache using fc-list. This may take a moment.')

이것은, 폰트 캐쉬를 빌드하는 작업이라고 하고, 최초만 표시됩니다. 다음 번 이후에는 나오지 않으므로 특히 신경 쓸 필요가 없습니다.

막대 그래프



막대 그래프는 pypぉt. 필드 r()을 사용합니다. 매개변수에서 필수는 x축 값 목록과 해당 y축 값 목록뿐입니다. align='center' 표시를 중앙으로 만들고 싶었기 때문에 지정합니다. 지정하지 않으면 왼쪽으로 들리므로 시도해보십시오.

그래프에 대한 결과 변환


word_counter.most_common(10)의 취득 결과는

list_word
[('の', 9198), ('。', 7486), ('て', 6798), ('、', 6772), ('は', 6418), ('に', 6177), ('を', 6047), ('と', 5486), ('が', 5339), ('た', 3968)]

라고 하는 형태입니다만, 그래프로 하기 위해서는, x축(단어)과 y축(그 출현 빈도)의 리스트로 나눌 필요가 있습니다. 이것은 이슈02에서 나온 zip()를 사용하면 간단합니다.

list(zip(*list_word))
[('の', '。', 'て', '、', 'は', 'に', 'を', 'と', 'が', 'た'), (9198, 7486, 6798, 6772, 6418, 6177, 6047, 5486, 5339, 3968)]

그래프에서 일본어를 사용할 때의 주의



디폴트의 ​​폰트에는 일본어의 문자의 데이터가 없기 때문에, 일본어를 표시하려고 하면 사각형이 되어 버립니다 (두부라고 부릅니다). 따라서 FontProperties 클래스에 지정해야 합니다. 이번에는 Ubuntu 16.04 LTS에 들어가 있었다TakaoGothic.ttf를 지정하고 있습니다.
덧붙여 디폴트의 폰트를 전환해 버리는 방법도 있는 것 같습니다만, 이번은 시도하고 있지 않습니다.

x축 값 범위



그래프의 축의 범위는 matplotlib가 적당하게 결정해 줍니다만, 이번의 경우, x축이 -2~10이 되어 버려, 그대로라면 왼쪽에 여백이 생겨 버립니다.



따라서 plt.xlim()에서 범위를 -1 ~ 10으로 설정합니다.

그리드 표시



그리드가 있던 것이 보기 쉽기 때문에, plt.grid() 로 y축만 표시해 보았습니다.

 
38번째 노크는 이상입니다. 실수 등이 있으시면 지적해 주시면 감사하겠습니다.

실행 결과에는 100개 노크에서 사용하는 코퍼스 데이터에 배포된 데이터의 일부가 포함됩니다. 이 제4장에서 사용하고 있는 데이터는 푸른 하늘 문고 로 공개되고 있는 나츠메 소세키의 장편 소설 '고배는 고양이이다'가 바탕으로 되어 있습니다.

좋은 웹페이지 즐겨찾기