LoginSignup
10
8

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-11-07

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

33. サ変名詞

サ変接続の名詞をすべて抽出せよ.

出来上がったコード:

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文ずつ辞書のリストを取得しサ変名詞を抽出
nouns = set()
nouns_test = []     # 確認用の出現順リスト
lines = neco_lines()
for line in lines:
    for morpheme in line:
        if morpheme['pos'] == '名詞' and morpheme['pos1'] == 'サ変接続':
            nouns.add(morpheme['surface'])
            nouns_test.append(morpheme['surface'])      # 確認用の出現順リストにも追加

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

実行結果:

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

端末(先頭部分)
['見当', '記憶', '話', '装飾', '突起', '運転', '分別', '決心', '我慢', '餓死', '訪問', '始末', '猶予', '遭遇', '返報', '勉強', '昼寝', '珍重', '経験', '供', '——', '同居', '観察', '断言', '同衾', '迫害', '尊敬', '生活', '剿滅', '議論', '所有', '憤慨', '観念', '御馳走', '掠奪', '代言', '失敗', '投書', '鑑定', '述懐', '処', '想像', '写生', '感心', '失笑', '揶揄', '欠伸', '自白', '造作', '彩色', '判然', '心中', '感服', '小便', '失敬', '予定', '失望', '漫罵', '増長', '報道', '退屈', '加減', '一睡', '運動', '嘆賞', '前後', '佇立', '身動き', '挨拶', '鼓動', '軽蔑', '肥満', '乱暴', '教育', '交際',

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

サ変接続の名詞とは

サ変接続というのは「〜する」の形が取れるものです。そのため品詞が名詞で、品詞細分類1がサ変接続のものを探せば良いようです。

ただしMeCabの結果には、品詞が名詞で品詞細分類1が接尾で品詞細分類2がサ変接続のものもあります。これは名詞に続く名詞で「〜する」の形が取れる、例えば「巨大『化』する」とか「世間『話』する」とかを指すようです。本来はこれらも抽出対象だと思いますが、問題30で品詞細分類2を取り込んでいないので判定ができません。これは仕様ということで。

基本的には前問で見ていた辞書のkeyと取り出す値のkeyを変えただけです。

2重ループの内包表記

2重ループでリストを作っていますので、この部分の内包表記に挑戦してみました。

main2.pyの後半部分
# 形態素解析
parse_neko()

# 1文ずつ辞書のリストを取得しサ変名詞を抽出
list_nouns = [morpheme['surface']
        for line in neco_lines()
        for morpheme in line
        if morpheme['pos'] == '名詞' and morpheme['pos1'] == 'サ変接続']
nouns = set(list_nouns)     # 重複除去

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

前問でshiracamusさんにコメントいただいた内容ほぼまんまです^^;

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


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

10
8
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
10
8