斜道倉庫

いろいろ遊んだことについて書いていく。

MeCabをPythonから使って遊びたい

内容

環境

コード

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import MeCab
import re

import pandas as pd

ATTR = ['表層形', '品詞', '品詞細分類1', '品詞細分類2', '品詞細分類3',
        '活用形', '活用型', '原形', '読み', '発音']

TEXT = "今日はいい天気だった。\n明日も晴れるといいな。くぁせdrftgyふじこlp\n"


def create_word_segmentation_func(cmd=''):
    """形態素解析を行う関数を生成する。

    MeCabを呼び出し、この時に呼び出したMeCabで形態素解析する関数を作成する。

    Args:
        cmd (str, optional): MeCab呼び出し時にMeCabに渡すコマンド
            出力形式(--???-format)は設定しないでください。処理がうまくいかなくなる可能性があります。

    Returns:
        (str) -> (pd.DataFrame): 形態素解析を行う関数

                    Args:
                        (str): 形態素解析したい文字列

                    Returns:
                        pd.DataFrame: 形態素解析を行う関数
                            [['表層形','品詞','品詞細分類1','品詞細分類2','品詞細分類3','活用形','活用型','原形','読み','発音'],\n
                            ...\n
                            ]

    """

    # MeCab起動
    # 同時に出力方法を設定しておく
    m = MeCab.Tagger(r'--node-format=%m\t%f[0]\t%f[1]\t%f[2]\t%f[3]\t%f[4]\t%f[5]\t%f[6]\t%f[7]\t%f[8]\n'
                + r' --unk-format=%m\t%f[0]\t%f[1]\t%f[2]\t%f[3]\t\t\t%f[6]\t\t\n'
                + r' --eos-format= '
                + ' ' + cmd)


    def word_segmentation(s):
        """形態素解析を行う関数

            具体的な説明は外の関数の戻り値参照
        """

        # MeCabで解析
        # 表層形,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
        # の形で戻ってくる
        d = m.parse(s)

        # words_infos に結果を詰めていく
        words_infos = []
        l = 0
        winfo = [''] * 10
        i = 0
        for k, r in zip(d, range(0, len(d))):
            if(k == '\t'):
                winfo[i] = d[l:r]
                i += 1
                l = r + 1
            elif(k == '\n'):
                winfo[i] = d[l:r]
                words_infos += [winfo]
                winfo = [''] * 10
                i = 0
                l = r + 1

        # テーブル words_infos を pd.DataFrame に変換して返す
        return pd.DataFrame(words_infos, columns=ATTR)


    return word_segmentation


if __name__ == '__main__':
    # 形態素解析
    word_segmentation = create_word_segmentation_func()
    words_infos = word_segmentation(TEXT)

    # 解析結果を '表層形 原形\n' で len(tword_info)行 で標準出力
    for k in words_infos[['表層形', '原形']].values:
        print(k[0] + ' ' + k[1])

    # 速度を計る
    import unittest

    class WS_TEST(unittest.TestCase):

        def test_ws(self):
            for i in range(100):
                word_segmentation(TEXT)

    unittest.main()

出力

今日 今日
は は
いい いい
天気 天気
だっ だ
た た
。 。
明日 明日
も も
晴れる 晴れる
と と
いい いい
な な
。 。
く くい
ぁせ
drftgy
ふじこ ふじこ
l l
p p
.
----------------------------------------------------------------------
Ran 1 test in 0.100s

OK

解説

基本的なこと

基本的なライブラリの入れ方や使い方は末尾にある参考ページへ。

MeCabの出力を使いやすくする

m = MeCab.Tagger(r'--node-format=%m\t%f[0]\t%f[1]\t%f[2]\t%f[3]\t%f[4]\t%f[5]\t%f[6]\t%f[7]\t%f[8]\n'
                + r' --unk-format=%m\t%f[0]\t%f[1]\t%f[2]\t%f[3]\t\t\t%f[6]\t\t\n'
                + r' --eos-format= '
                + ' ' + cmd)

MeCabの初期化時にフォーマットを指定することで出てきた結果を後で使いやすくする。
今回は、tvs形式で出力させている。こうすることで、非常にデータの扱いやすさが増す。
具体的な指定方法は、MeCab公式ページ->目次->高度な使い方->出力フォーマットの詳細定義 から参照できる。

できるだけ早くテーブルを作りたい!!

        # MeCabで解析
        # 表層形,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
        # の形で戻ってくる
        d = m.parse(s)

        # words_infos に結果を詰めていく
        words_infos = []
        l = 0
        winfo = [''] * 10
        i = 0
        for k, r in zip(d, range(0, len(d))):
            if(k == '\t'):
                winfo[i] = d[l:r]
                i += 1
                l = r + 1
            elif(k == '\n'):
                winfo[i] = d[l:r]
                words_infos += [winfo]
                winfo = [''] * 10
                i = 0
                l = r + 1

pythonのstr型はことあるごとにコピーが発生するため文字列操作が結構遅い。
append(other) はotherのコピーを作ってそれを末尾に追加し、
list += other はotherの参照を末尾に追加する。
したがって、捨ててしまうwinfoを+=でwords_infos に結合させて最適化している。
また、リストの初期化は ['']*10 が早い気がする。

感想

pythonの文字列やリストの操作が結構重いみたい。最初のほうは、MeCab出力を一行ずつ読み取って、正規表現で分割して、appendで足して次の行へ…としていたが、いろいろ最適化をしてみて10倍ぐらい早くなった。pythonもメモリのコピーついてよく考えないと大変なことが分かった。
今回の実装で結構早く形態素解析できるようになったので、いろいろできそう。機械学習を勉強して組み合わせて何かやってみたいなあ…。