2018年04月22日

言語処理100本ノックでPython入門 #38 - matplotlibでヒストグラム

  
今日は言語処理100本ノック 2015の問題38です。

■ 問題
夏目漱石の小説『吾輩は猫である』の文章(neko.txt)をMeCabを使って形態素解析し,その結果をneko.txt.mecabというファイルに保存せよ.このファイルを用いて,以下の問に対応するプログラムを実装せよ. なお,問題37, 38, 39はmatplotlibもしくはGnuplotを用いるとよい.

38. ヒストグラム
単語の出現頻度のヒストグラム(横軸に出現頻度,縦軸に出現頻度をとる単語の種類数を棒グラフで表したもの)を描け.


No37で求めた、単語の出現数のデータをさらに加工して、出現する単語の数を求め、それを元にグラフを描いています。


■ Pythonのコード
import re
import matplotlib.pyplot as plt
 
def analyze():
    lines = []
    sentence = []
    with open('neko.txt.mecab', 'r', encoding='utf8') as fin:
        for line in fin:
            words = re.split(r'\t|,|\n', line)
            if words[0] == 'EOS':
                if sentence:
                    lines.append(sentence)
                    sentence = []
                continue
            sentence.append({
                "surface": words[0],
                "base": words[7],
                "pos": words[1],
                "pos1": words[2],
            })
    return lines
 
def getFrequency(lines):
    words = {}
    for sentense in lines:
        for word in sentense:
            if word['pos'] == '記号':
                continue
            if word['surface'] in words.keys():
                words[word['surface']] += 1
            else:
                words[word['surface']] = 1
    return words
 
def getHistogramData(words):
    hist = {}
    for word in words.items():
        if word[1] in hist.keys():
            hist[word[1]] += 1
        else:
            hist[word[1]] = 1
    return words
 
def plotHistgram(data):
    xs = [x[1] for x in data]

    plt.rcParams['font.family'] = 'Meiryo' 
 
    plt.hist(xs, bins=25, range=(1, 25))
    plt.xlim(xmin=1, xmax=25)
    plt.xlabel('単語の出現頻度')
    plt.ylabel('単語の種類数')
    plt.show()
 
def main():
    article = analyze()
    words = getFrequency(article)
    histData = getHistogramData(words)
    sortedData = sorted(histData.items(), key=lambda x: x[1], reverse=True)
    print(sortedData[0:20])

    plotHistgram(sortedData)
 
if __name__ == '__main__':
    main()

■ ヒストグラムの描画

plotHistgram関数が、ヒストグラムを描画している関数です。

最初に書いたコードだと、なんとほとんどの単語が1回しか現れませんでした。 そのため、デフォルト設定のままhistメソッドを呼び出すと、まったく意味のわからないグラフになっていたので、range引数を指定して範囲を上位1-25に限定しました。

X軸は
plt.xlim(xmin=1, xmax=25)
で、範囲を設定できます。

Y軸のタイトルは縦書きにしたかったのですが、やり方がわかりませんでした。

■ 結果
nlp38

グラフ描画とともに、出現頻度の多い単語を20個表示しています。
 
[('の', 9194), ('て', 6868), ('は', 6420), ('に', 6243), ('を', 6071), ('と', 5508), ('が', 5337), ('た', 3988), ('で', 3806), ('も', 2479), ('ない', 2390), ('だ', 2363), ('し', 2322), ('から', 2032), ('ある', 1728), ('な', 1613), ('ん', 1568), ('か', 1530), ('いる', 1249), ('事', 1207)]