言語処理100本ノック 2015 第4章 35〜39


言語処理100本ノック 2015」の「第4章: 形態素解析」、35〜39。
内容としては以下の記事の続きになります。

「言語処理100本ノック 2015」の「第4章: 形態素解析」、30〜34。 30. 形態素解析結果の読み込み 形態素解...

35. 名詞の連接

名詞の連接(連続して出現する名詞)を最長一致で抽出せよ.

言語処理100本ノック 2015 第4章 30〜34」の「31. 動詞」〜「33. サ変名詞」の「get_words」関数の書き直しのみで対応可能。品詞が名詞である間wordに追加して、名詞以外になったタイミングで表層形を接続してwordsに追加、という処理です。

def get_words(morphemes):
    words = []

    for line in morphemes:
        word = []

        for morpheme in line:
            if morpheme['pos'] == '名詞':
                word.append(morpheme['surface'])
            else:
                if len(word) > 1:
                    words.append(''.join(word))

                word = []

    if len(word) > 1:
        words.append(''.join(word))

    return words

36. 単語の出現頻度

文章中に出現する単語とその出現頻度を求め,出現頻度の高い順に並べよ.

「単語等を抽出」ではなく「頻度を抽出」が課題なので、関数名を「get_words」ではなくて「get_freq」にしてみます。呼び方はここまでのget_wordsと同様です。

def get_freq(morphemes):
    c = Counter(x['surface'] for x in chain.from_iterable(morphemes))
    return c.most_common()

形態素のリストのリストになっているmorphemesを、itertoolschan.from_iterableで形態素のリストに平坦化。表層形でカウントするか基本形でカウントするか微妙ですがここでは表層形でカウントすることにしてみました。
collectionsCounterを使うと、極めて簡単にカウントすることが可能です。most_commonを使うことで頻度上位からソートした結果を取得可能です。

37. 頻度上位10語

出現頻度が高い10語とその出現頻度をグラフ(例えば棒グラフなど)で表示せよ.

出力の仕方が今までと違ってグラフ出力になります。
4章の冒頭に「なお,問題37, 38, 39はmatplotlibもしくはGnuplotを用いるとよい」という記載がありますので、matplotlibを使ってみます。
まずプログラム全体を示します。

import argparse
from collections import Counter
from itertools import chain
import matplotlib as mpl
import matplotlib.pyplot as plt


def read_morphemes(lines):
    morphemes = []

    for line in lines:
        if line.rstrip() == 'EOS':
            if len(morphemes) > 0:
                yield morphemes

            morphemes = []
        else:
            t1 = line.split('\t')
            t2 = t1[1].split(',')
            m = {'surface': t1[0], 'base': t2[6], 'pos': t2[0], 'pos1': t2[1]}
            morphemes.append(m)


def get_freq(morphemes):
    c = Counter(x['surface'] for x in chain.from_iterable(morphemes))
    return c.most_common(10)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('infile')
    args = parser.parse_args()

    with open(args.infile, mode='r') as f:
        morphemes = read_morphemes(f)
        freq = get_freq(morphemes)

    x = list(range(1, 11))
    y = [f[1] for f in freq]
    lbl = [f[0] for f in freq]
    mpl.rcParams['font.family'] = 'AppleGothic'
    plt.bar(x, y, tick_label=lbl)
    plt.show()


if __name__ == '__main__':
    main()

まず「出現頻度が高い10語」という要求から「get_freq」関数で使っているmost_commonの引数で10を指定。
グラフ表示のため「matplotlib」と「matplotlib.pyplot」をimport。
棒グラフの下のラベルとして単語の表層形を表示するためにtick_labelで指定していますが、このままだと日本語文字が□になってしまうので、日本語を出せるフォントを指定。自分はmac環境なので、ApplceGothicを指定することで日本語表示させています。

表示結果はこんな感じです。

38. ヒストグラム

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

これもmatplotlibを使います。37と違う関数はget_freqとmainのみなので、そこだけ以下に示します。

def get_freq(morphemes):
    c = Counter(x['surface'] for x in chain.from_iterable(morphemes))
    return c.most_common()


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('infile')
    args = parser.parse_args()

    with open(args.infile, mode='r') as f:
        morphemes = read_morphemes(f)
        freq = get_freq(morphemes)

    data = [f[1] for f in freq]
    mpl.rcParams['font.family'] = 'AppleGothic'
    plt.hist(data, bins=50, range=(1, 50))
    plt.show()

この課題では上位10語とか絞り込んではいけないので、get_freqのmost_commonの引数を削除。
main関数の方は棒グラフではなくヒストグラムを出すため、barではなくhistを使用。
ここにデータを投入するだけで勝手にヒストグラム化してくれるので簡単。
ただ、そのままにしてしまうと、ほとんどゼロがずっと続くだけのヒストグラムになってしまうので、出現頻度が50までに絞り込んで表示することにしました。

表示結果は以下の通りです。

39. Zipfの法則

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

まず「Zipfの法則」ですが、Wikipediaによると「出現頻度が k 番目に大きい要素が全体に占める割合が 1/k に比例するという経験則である」
だそうです。

今回は散布図で描いてみました。散布図はscatterで描くことができます。
38の課題と異なるのはmainでの描画部分だけなので、そこだけ抽出して記載しておきます。

    data = [f[1] for f in freq]
    mpl.rcParams['font.family'] = 'AppleGothic'
    plt.xscale('log')
    plt.yscale('log')
    plt.scatter(list(range(1, len(data) + 1)), data)

plt.xscale(‘log’)とplt.yscale(‘log’)で両対数グラフにしています。

表示結果は以下の通りです。

スポンサーリンク

フォローする

スポンサーリンク