LoginSignup
7
2

More than 5 years have passed since last update.

素人の言語処理100本ノック:35

Last updated at Posted at 2016-11-12

言語処理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を用いるとよい.

35. 名詞の連接

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

出来上がったコード:

main.py
# coding: utf-8
import MeCab
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()

# 1文ずつ辞書のリストを取得し抽出
list_series_noun = []       # 出現順リスト、重複あり
for line in neco_lines():
    nouns = []      # 見つけた名詞のリスト
    for morpheme in line:

        # 名詞ならnounsに追加
        if morpheme['pos'] == '名詞':
            nouns.append(morpheme['surface'])

        # 名詞以外なら、それまでの連続する名詞をlist_series_nounに追加
        else:
            if len(nouns) > 1:
                list_series_noun.append("".join(nouns))
            nouns = []

    # 名詞で終わる行があった場合は、最後の連続する名詞をlist_series_nounに追加
    if len(nouns) > 1:
        list_series_noun.append("".join(nouns))

# 重複除去
series_noun = set(list_series_noun)

# 確認しやすいようlist_series_nounを使って出現順にソートして表示
print(sorted(series_noun, key=list_series_noun.index))

実行結果:

長いので先頭部分のみです。

端末(先頭部分)
['人間中', '一番獰悪', '時妙', '一毛', 'その後猫', 'こんな片輪', '一度', 'ぷうぷうと煙', '邸内', '三毛', '暖かそう', '書生以外', '再びおさん', '同じ事', '四五遍', 'この間おさん', '三馬', '御台所', 'ら内', 'まま奥', '住家', 'ぎりほとんど', '勉強家', '勤勉家', '二三ページ', '主人以外', '限り吾輩', '朝主人', 'その後いろいろ経験', '一番心持', '二人', '一つ床', '一人', '最後大変', '——こと', '——猫', '神経胃弱性', '尻ぺたをひどく', '言語同断', '家内総がかり', '筋向', '白君', '度毎', '先日玉', '四疋', '三日目', '猫族', '完くし', '家族的生活',

結果全体はGitHubにアップしています。

ロジックについて

parse_neko()neco_lines()前問と同じです。

今回はコメントを少し多めにいれてみました。名詞が続く間はnounsに追加していって、名詞以外がきた時にそれまでにためたnounsを連結してlist_series_nounに追加する流れです。
なお、これだと最後が名詞で終わった場合にlist_series_nounに追加されないので、1行分のループが終わった後にも同じ処理を入れています。ただし今回の『吾輩は猫である』は必ず行が句点で終わるので、ここで追加されることはありません。

 
36本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。


実行結果には、100本ノックで用いるコーパス・データで配布されているデータの一部が含まれます。この第4章で用いているデータは青空文庫で公開されている夏目漱石の長編小説『吾輩は猫である』が元になっています。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2