2018年04月25日

言語処理100本ノックでPython入門 #39 - matplotlibで散布図を作成

  

いよいよ言語処理100本ノック 2015の第4章最後の問題39です。

■ 問題


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

39. Zipfの法則
単語の出現頻度順位を横軸,その出現頻度を縦軸として,両対数グラフをプロットせよ.

■ Pythonのコード

import re
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['surface'] in words.keys():
                words[word['surface']] += 1
            else:
                words[word['surface']] = 1
    return words
 
def getScatterData(words):
    data = [x[1] for x in words.items()]
    data = sorted(data, key=lambda x: x, reverse=True)
    return range(1, len(data)+1), data
 
def plotScatter(x, y):
    plt.rcParams['font.family'] = 'Meiryo'  
    plt.scatter(x, y, s=2)
    plt.xscale("log")
    plt.yscale("log")
 
    plt.xlabel('出現頻度順位')
    plt.ylabel('出現頻度')
    plt.show()
 
def main():
    article = analyze()
    words = getFrequency(article)
    x, y = getScatterData(words)
 
    plotScatter(x, y)
 
if __name__ == '__main__':
    main()

■ 散布図を描く

以下のようにして両対数目盛の散布図を描いています。
plt.scatter(x, y, s=2)
plt.xscale("log")
plt.yscale("log")

軸を対数目盛にするには、xscale('log"0),yscale('log"0) を使います。

散布図は、scatter(x, y, s=2) です。

sは点のサイズを表しています。 Pythonは関数で複数の値を返すのが簡単で良いですね。

ところで、Zipfの法則ってなに?

Wikipediaによると

ジップの法則(ジップのほうそく、Zipf's law)あるいはジフの法則とは、出現頻度が k 番目に大きい要素が全体に占める割合が 1/k に比例するという経験則である。Zipf は「ジフ」と読まれることもある。また、この法則が機能する世界を「ジフ構造」と記する論者もいる。

とのことらしいです。 2番目の出現頻度は、1/2 3番目は1/3, 4番目は、1/4となるという法則ということですね。

■ 結果

nlp39

第4章もこれで終わりです。いよいよ第5章。やっとクラスを使います。