yoraba build

備忘録を兼ねた技術ブログ

xonshで形態素解析

形態素解析

形態素解析は日本語の自然言語処理を行う上でよく使われる技術です。掻い摘んで言うと、文を品詞分解するというものです。 分解した後は文章を英語のようにスペースで区切る、所謂分かち書きを行ったり、単語の出現回数を数えたり、といった処理を行うことが出来ます。 そうして出来上がったデータは、LexRankや機械学習などに用いることが出来るのですが、今回は扱いません。 文章から単語を抽出するという処理だけでも、日常的に有用だと思ったので、形態素解析を気軽に使えるようなスクリプトを作りたいと思いました。

mecabインストール

形態素解析を行うためのパッケージとしてmecabを使用します。インストール方法については方方に情報があるので、コマンドだけ記載します。

sudo apt install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file swig
sudo apt-get install mecab libmecab-dev mecab-ipadic mecab-ipadic-utf8

# ユーザー辞書をダウンロードしてインストールします。
# 辞書のアップデートに備えて覚えやすいディレクトリを作成して移動してから以下のコマンドを実行します。
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
sudo ./bin/install-mecab-ipadic-neologd -n -a

pip install mecab-python3

xonshスクリプト

mecabにはpython、コマンド実行とファイルアクセスにはシェルを使いたいのでxonshスクリプトを書きます。 スクリプトが書かれたxshファイルを、.xonshrcで起動時インポートするのが楽です。

yoraba.hatenablog.com

カレントディレクトリを起点として再帰的に全てのファイルを連結する。

解析したいテキストを一つのファイルに集約するのも手間なので、コマンド一発でカレントディレクトリを起点にファイルを再帰的に検索して連結出来るようにします。

def _get_relative_path_tree(args, stdin=None):
    '''
    sudo apt install tree
    '''
    return $(tree -fi --noreport).split()

aliases['get_relative_path_tree'] = _get_relative_path_tree

def _cat_all(args, stdin=None):
    result = ''
    for item in _get_relative_path_tree([]):
        result += $(cat @(item))
    return result

aliases['cat_all'] = _cat_all

単語の抽出とカウント

文章から単語を抽出してカウントし、降順に並び替えた辞書を返却します。 第一引数は文字列、それ以降は、名詞、形容詞などといった品詞です。

def _node_freq_count(words, word):
    if word in words:
        words[word] += 1
    else:
        words.setdefault(word, 1)

def _mecab_analyze(args, stdin=None):
    import MeCab
    mecab_dir = $(mecab-config --dicdir).strip() + '/mecab-ipadic-neologd'
    mtag = MeCab.Tagger(f"-d {mecab_dir}")
    text = args[0]
    parts = args[1:]
    nodes = mtag.parseToNode(text)
    result = {}
    while nodes:
        if nodes.feature.split(",")[0] in parts:
            word = nodes.surface
            _node_freq_count(result, word)
        nodes = nodes.next
    result = dict(sorted(result.items(), key=lambda x:x[1], reverse=True))
    return result

aliases['mecab_analyze'] = _mecab_analyze

mecab-configコマンドで辞書のディレクトリを取得し、ユーザー辞書フォルダ名を連結したものを、Tagger初期化時のパラメータに渡しています。 sorted()はタプル入りリストを返すのですが、xonsh関数でタプル入りリストを返却するとエラーになるのがハマりポイントでした。

実行

以下のようなコマンドで実行できます。

mecab_analyze $(cat_all) 名詞

f:id:yoraba:20191105234311p:plain