LoginSignup
3
7

More than 5 years have passed since last update.

いまさら聞けない日本語前処理をさくっと済ませるための準備

Posted at

TL;DR

日本語を対象にした自然言語処理において、
あまりフォーカスされない割に(そしてその故に)初心者が戸惑う「前処理」を担うクラスを用意して、
気が向いたときに素早く日本語分析を始められるように準備してみました。
https://github.com/kazuhirokomoda/nlp_jp_template

きっかけ

ここ最近、自然言語処理からすっかり遠ざかっていました。
昔はもう少し楽しくデータをいじっていた気がしたので、なんで遠ざかっていたのか、少し考えてみました。

結果がすぐに出ない

「何か分析したい」と思ってから、納得のいく結果が出るまで、それなりに時間がかかります。
確かに、分析ってそういう側面があるものなのですが・・・そこが逆に楽しいところでもあるので、遠ざかっていた直接の原因ではなさそうかな・・・。

データ集めはちょっとめんどくさい

より正確にはデータ整形でしょうか。
「このデータを使えば面白そう」と思っても、元データがプログラム処理に向いた形で公開されているとは限りません。

前処理

特に日本語は、単語の区切りが自明じゃないので、前処理がもう一手間かかってめんどくさい・・・。
分析に入るまでの準備が手間だと感じるのは、きっと自分だけじゃないはず。

というわけで

なるべくスムーズに自然言語処理のスタートラインに立てるように、
(主に)今後の自分のために作ったプログラムの紹介になります。

※ 実際には、MeCab と scikit-learn で日本語テキストを分類する を自分用に多少カスタマイズさせていただいた、という方が正確ですが。。。

環境

Mac OS X 10.10.5
Python 3.5.1
Anaconda 2.4.1

やったこと

1行を1文書として、日本語のテキストファイルを用意します。
内容は、特に理由はないですが、Wikipediaの総理大臣から。
https://github.com/kazuhirokomoda/nlp_jp_template/blob/master/data/train_test.txt

word_divider.py
def make_documents_from_file(file_path):

file_pathで指定したファイルを読み込み、1行分の内容を1要素とする配列を返します。

word_divider.py
class WordDivider:
...
    def __init__:

クラス変数の設定と、MeCabの初期化をします。

TARGET_CATEGORIES = ["名詞", "動詞"] #["名詞", "動詞", "形容詞", "副詞", "連体詞", "感動詞”]

で含めたい品詞を指定します。

自立語(単独で一つの文節を作ることができる単語)でないものは、いったん分析の対象外にしたかったので、

REMOVE_SUB_CATEGORIES = ["非自立”]

で指定しました。

word_divider.py
def set_stopwords(self):

ストップワード(一般的であったり、出現頻度が多すぎたり、などの理由で処理対象外とする単語)を指定します。
日本語のストップワードを集めたデータがあったので、今回は便宜的にそれをダウンロードして使用します。

word_divider.py
def extract_words(self, text):

textで文字列を受け取ります。

normalize_neologd.py
def normalize_neologd(s):

このモジュールは、こちらをまるごと使わせていただきました。
https://github.com/neologd/mecab-ipadic-neologd/wiki/Regexp
mecab-ipadic-NEologdは新語を含むMeCab用の辞書みたいです。

mecab-ipadic-NEologd is customized system dictionary for MeCab.
This dictionary includes many neologisms...

word_divider.py
        node = self.tagger.parseToNode(text)
        while node:
            features = node.feature.split(',')

正規化処理を施した文字列を形態素単位に区切り、形態素ごとに処理します。featuresに形態素解析の結果が入っています。
parseToNodeとparseの速度の比較については、こちらを参考にして試してみたいと思います。特に大量のデータを処理するときは、気をつけないと。。。
http://qiita.com/yukinoi/items/81a707c1317c97f5fdf9

word_divider.py
                if features[self.INDEX_ROOT_FORM] == "*":
                    word_to_append = node.surface
                else:
                    # prefer root form
                    word_to_append = features[self.INDEX_ROOT_FORM]

原形があれば原形、なければ表層形を使います。

使い方

https://github.com/kazuhirokomoda/nlp_jp_template/blob/master/run.py
から、今回記事に書いた部分を抽出して・・・。

run.py
# -*- coding: utf-8 -*-

# imports
import sys
import MeCab
from urllib.request import urlopen

# local imports
from word_divider import *

text_path_train_test = 'data/train_test.txt'

if __name__ == '__main__':

    # Read file and make "documents" as array
    documents = make_documents_from_file(text_path_train_test)
    print('Documents (split by lines): ')
    print(documents)
    print()

    # Make an instance of WordDivider for dividing Japanese text
    wd = WordDivider(is_normalize=True, remove_stopwords=True)

うん、手早く日本語前処理をできそうな気がしてきた。

next action

日本語前処理を担ってくれるクラスを作ったことで、何かデータを集めて分析したい気分になってきました。

  • 分析したいデータを集めたり(集めたりしないといけないことには変わりない・・・笑)
  • 自然言語処理でよく使われるBag-of-words(BoW)形式に変換したり
3
7
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
3
7