DATUM STUDIOブログ
「楽屋」

pythonによる日本語前処理備忘録

はじめに

こんにちは。DATUM STUDIOの安達です。

最近社内で日本語のテキストを用いた自然言語処理でよく質問を受けるのですが、前処理についてはそこそこ同じような内容になるため、本記事では社内共有の意味も込めて前処理に関して用いてきた&用いれそうな手法を列挙します。

比較的同じ内容を扱った既存の記事としては以下のようなものもあり、読者の方はこれらも参考にされて要件に合わせて取捨選択してください。

本記事における使用言語、環境は以下の通りです。

  • osx 10.13.6
  • anaconda 5.2.0
  • python 3.5.2

Table of contents

  • 形態素解析段階での前処理

    • 文字表現の正規化
    • URLテキストの除外
    • Mecab + neologd 辞書による形態素解析
  • 形態素解析後の前処理

    • 品詞による絞り込み
    • 特定の名詞の除外
  • 文書ベクトル化段階での前処理

    • 単語頻度による除外
    • 文書頻度による除外
  • まとめ

形態素解析段階での前処理

文字表現の正規化

pythonパッケージneologdnは日本語テキストに対して、Mecab+neologd辞書を用いる前に推奨される正規化(表記ゆれの是正)を加えてくれます。Mecabとneologd辞書については後述します。

neologdnライブラリのインストール

neologdnそのものはneologd辞書がなくても動作します。

URLテキストの除外

テキストとしてURLやエスケープコードが混じっているケースではこれらを形態素解析をする前に予め除外します

  • エスケープコード(&:amp,>:gt,<:lt…)
  • http, httpsで始まるURL

URLの文字列については単純な正規表現を用いて以下のように省けますが、URLが複雑なケースでは更に工夫が必要かもしれません

Mecab + neologd 辞書による形態素解析

日本語は膠着語とよばれ、英語のようにテキスト内の単語それぞれがスペースで分かれている言語ではないです。

それ故前処理にあたってはテキストを単語単位に分割する必要があります。これを分かち書きといい、それには形態素解析エンジンが用いられることが多いです。

形態素解析エンジンには処理速度や形態素の網羅性から、ほとんどの案件でmecab + neologd辞書を用いています。処理対象のテキストによっては、対象ドメイン(e.g. 医療系用語, 通信系用語)特有の形態素も辞書として追加します。

Mecab + neologdのインストール

Mecabをインストールしたら、pythonのMecabバインディングをインストールします

Mecabの出力はいろいろな形式で出力できますが、形態素品詞体系としてChasen品詞体系を用いることが多く、Mecabの形態素タグ付けをするオブジェクトであるタガーを取得する際に -Ochasen フラグを指定します。

また、-d フラグで辞書も指定できるため、

で出力されるneologd辞書のパスを指定します

このような形式の出力については、後々処理しやすいようpandasのDataFrameに格納しておくと便利です。

最後のカラム名の意味は形態素解析の結果に対応しており、それぞれ以下の意味を持ちます。

  • surface(表層型): テキスト中の表現型
  • spell(スペル): どう発音するか
  • orig(原型): 形態素の原型、例えば動詞の活用形によっては原型と表層型が異なる場合があります。
  • type : 形態素の品詞型
  • katsuyoukei : 活用形
  • katsuyoukata : 活用型

形態素解析後の前処理

品詞による絞り込み

対象や目的にもよりますが、多くのタスクでは名詞を中心に抽出します。先程のように形態素解析の結果で得られた品詞についてはツールごとに品詞体系なるものが定められており、-Ochasen フラグではChasen品詞体系が用いられます。

Chasen品詞体系のうち、以下の3種類はよく用います。

  • 名詞-一般
  • 名詞-サ変接続
  • 名詞-固有名詞

サ変は聞き慣れない人もいると思いますが、「くしゃみ」や「握手」などの後に「〜する」を置くと動詞として利用できる種類の名詞のことです。

品詞タグ「名詞-固有名詞」の下には小さなカテゴリとして「人名」や「組織」、「地域」も続くため、これらについてもタスクによっては品詞の型による除外が可能です。

特定の名詞の除外

名詞の中でも以下の類のものはタスクとして抽出の必要のないケースが多く、除外することが多いです。(といってもタスクによっては除外しない方がいい時もありますが)

  • 数値 + 単位(1日、2年、5個…)
  • 漢数字 + 単位(一個、十時…)
  • 日付
  • 季節に関する用語(春夏秋冬)
  • 曜日(月火水木金土日)
  • 方角(北南西東)
  • 絵文字(😀😁😂🍎等)
  • その他ストップワード

中でもうっかり忘れてしまいがちなのが絵文字で、neologd辞書には原型が通常の日本語として登録されているため、除外を忘れると原型による集計の段階でテキストには現れなかったような文字が大量に含まれてしまうことになります。

絵文字の除外はunicodeの特定の範囲を正規表現で指定することで実現可能です。

unicodeのバージョンが変更されるたびに絵文字のunicode範囲が次第に広がっていっているのが辛いところです。

文書ベクトル化段階での前処理

単語頻度による除外

高頻度や低頻度の単語はTFIDF特徴量に於いて頻度による重み付けがされた場合でも頻度の影響が強いケースがあるため、対象の単語を除外することがあります。除外方法には複数あり、主に以下の2つが候補として挙げられます。

  1. 頻度順に単語を並べた時に上位下位x%に入るか
  2. 頻度を用いたクラスタリングによるクラスタ除外

頻度順に単語を並べた時に上位下位x%に入るか

1番目については文書中の単語の頻度を集計した上で頻度でソートします。頻度でソートした結果で除外すべき対象に含まれるかどうかを単語頻度のランキングで決定します。

例えば blog という単語が全体の文書のうち、頻度200で文書全体2000単語のうちの100位に入っていたとします。もしもしきい値xを5%と定めているのであれば blog という単語を除外対象として含むことになります。

ドキュメント郡から単語頻度を取得するサンプルを動かすためにまず以下のシェルで健康アドバイスデータセットをダウンロードします。

そしてダウンロードしたxmlデータから文書IDと名詞を中心とした分かち書き表現からなるデータフレームを取得します。

このlifelogbowdfはドキュメントID(lifelog_id)と対応するドキュメントを正規化した上で名詞を中心に形態素を抽出し、分かち書きしたテキスト(bow)が含まれるものになります。

このテキストに含まれる単語を文書全体で集計してみます。

最終的に得られたデータフレームは頻度順位がインデックスに対応しており、このようにして頻度の上位x%に含まれる単語を特定することで前処理に活かせます。

頻度を用いたクラスタリングによるクラスタ除外

2番目の頻度を用いたクラスタリングは単語と頻度の対をサンプルとみなしてその集合を頻度という1次元の量によってクラスタリングします。K-meansによるサンプルコードを下記に挙げます。

このメソッドに単語頻度のデータフレームを与えることで新しくclusterカラムに’高中低’の頻度情報が紐ついたデータフレームが得られることになります。その中から適宜高頻度、低頻度に含まれる単語を除外して最終的な対象の単語を定められます。

文書頻度による除外

先程の単語そのものの頻度ではなく文書頻度とは単語について全体の文書のうちどのくらいの文書に渡ってその単語が含まれているかを示す量になります。これを用いた単語の除外はscikit-learnの CountVectorizer,TfidfVectorizerの初期化引数として含まれるmaxdf, mindfを用いることで実現可能です。

まとめ

いかがでしたでしょうか。文書中のソースコードではpandasの操作で少々トリッキーなところがあったかもしれません。自然言語処理における前処理の概観として本記事が参考になれば幸いです。

引用

Tetsuaki Nakamura, Takashi Awamura, Yiqi Zhang, Eiji Aramaki, Daisuke Kawahara and Sadao Kurohashi, Toward an Advice Agent for Diet and Exercise Based on Diary Texts, In proceedings of 2015 AAAI Spring Symposium Series – Ambient Intelligence for Health and Cognitive Enhancement, pp.43-48, Mar.2015.