CreateField Blog

オープンソースを使って個人でWebサービスを開発・運営していたブログ

専門用語を自動抽出するTermExtractをDockerで簡単に使えるようにしました

はじめに

品詞のつながりや出現頻度、学習情報から複合語らしきキーワードを自動で抽出するPerlモジュールTermExtractが公開されています。

これを利用すれば、形態素解析済みのテキストを食わせるだけでそこそこそれらしい専門用語をたくさん得ることができます。

このTermExtractは、ソースからインストールする必要があったり、EUC環境であったり形態素解析後のデータを入力に必要としたりなかなかめんどくさいです。

そこで、MeCabとTermExtractが自動で環境構築されるDockerファイルを作りました。

https://github.com/naoa/docker-termextract

このDockerファイルでは、正規表現フィルタや形態素解析、コスト推定などを自動でやってくれるPerlスクリプトも自動で導入されるようになっています。

これでDockerを実行できる環境があれば、プレーンなテキストをパイプでdocker runコマンドに渡すだけで、簡単に専門用語を抽出することができます。

また、形態素解析辞書の出力形式も用意しているので、出力結果を簡単に形態素解析辞書に組み込むこともできます。

Dockerのインストール

Dockerが入っていない場合、まずはDockerをインストールしてください。Dockerは今結構旬なプロダクトなので導入に困ることはないんじゃないかなと思います。 CentOSならepelリポジトリを有効にしてyum install -y docker-ioだけで導入できます。

イメージ構築

まずは、Dockerイメージを作成します。コンテナとファイル共有するために/var/lib/termextractディレクトリを作成しています。

% git clone git@github.com:naoa/docker-termextract.git
% cd docker-termextract
% mkdir /var/lib/termextract
% docker build -t naoa/termextract .

Docker上のTermExtractを実行して専門用語を抽出

echoコマンドやcatコマンドを使って、パイプ越しにプレーンテキストをdocker runコマンドに渡します。

% echo "印刷用紙を複合機で印刷する。" | \ 
  docker run -v /var/lib/termextract:/var/lib/termextract \
  -a stdin -a stdout -a stderr -i naoa/termextract termextract_mecab.pl
複合機                                298.54
印刷用紙                              14.01

Dockerコンテナ内に環境構築済みのTermExtractによって、「複合機」と「印刷用紙」という複合語を得ることができました。

数値は、重要度を示しています。学習機能を自動でオンにしているため、複数回実行すると重要度はどんどんあがっていきます。学習機能の詳細は本家サイトをご確認ください。学習用のDBは、/var/lib/termextract/stat.db/var/lib/termextract/comb.dbに作成されます。分野を変える場合やリセットする場合は、ファイルを移動するなり削除するなりしてください。

7/10追記

コマンドが長くてめんどくさいですが、エイリアスをはれば短縮できます。常用的に使う場合は、~/.bashrcなどの起動スクリプトに書けばよいです。

% alias termextract="docker run -v /var/lib/termextract:/var/lib/termextract \
  -a stdin -a stdout -a stderr -i naoa/termextract termextract_mecab.pl"

正規表現フィルタ

TermExtractでは、品詞のつながりや出現頻度、学習情報から複合語らしきものを結合しようとします。しかしながら機械的な処理なので誤って結合されることも結構あります。

形態素解析前にプレーンテキストから除去する文字列の正規表現パターンが記載されたファイル/var/lib/termextract/pre_filter.txtと、複合語抽出後に除外させる正規表現パターンが記載されたファイル/var/lib/termextract/post_filter.txtを用意しています。 TermExtractを実行しながらこれらのファイルを編集して適宜フィルタルールを調整することにより極力ノイズを減らすことができます。

出力形式

出力形式には、以下のように専門用語と重要度を出力してくれるモード、直接、IPAdic辞書の形式で出力してくれるモードを用意しています。

--output 説明
1 または 引数なし 専門用語+重要度
2 専門用語のみ
3 カンマ区切り
4 IPAdic辞書形式(自動コスト推定)
5 IPAdic辞書形式(文字列長)

せっかく自動コスト推定までしてくれる環境を作ったので、ついでにTermExtractを使わずに行ごとの単語リストをコスト推定してくれるモードも用意しています。

オプション 説明
--no_term_extract 専門用語抽出せずにコスト推定のみ実行

IPAdic辞書形式(自動コスト推定)

--output 4を指定するとMeCabで自動コスト推定したIPAdic形式の文字列が出力されます。

% echo "印刷用紙を複合機で印刷する。" | \
  docker run -v /var/lib/termextract:/var/lib/termextract \
  -a stdin -a stdout -a stderr -i naoa/termextract termextract_mecab.pl --output 4
複合機,1285,1285,7336,名詞,一般,*,*,*,*,複合機,*,*,ByTermExtractEst
印刷用紙,1285,1285,7336,名詞,一般,*,*,*,*,印刷用紙,*,*,ByTermExtractEst

これを利用すれば、プレーンテキストを入力するだけで、自動コスト推定までしたIPAdic辞書を簡単に追加することができます。

なお、自動コスト推定のアルゴリズムはよくわかっていませんが、自動推定によって追加した用語は推定コストが割り振られているため文脈によっては必ず区切られるとは限りません。

既存の形態素解析結果を極力壊したくない場合は、こちらを利用する方がいいかもしれません。

GroongaやElasticsearch、Solrなどの全文検索では、単語の前後の出現位置もマッチさせる完全転置索引方式をとっているため、コストを考慮せずに単純に用語を追加しただけの辞書を用いると検索漏れが多くなる惧れがあります。 全文検索では極力精度がおちないように慎重にチューニングするかNgramと併用するなど工夫が必要です。

MeCabには、既存の学習済みモデルと少量の学習データ(1行分の正解の形態素解析結果ぐらい)を使った再学習機能も備わっています。

再学習機能は、少量とはいえ自前で正解の形態素解析結果をつくる必要があるため、多数の用語ごとに学習データを準備するのはかなり大変です。しかし、ちゃんとドメイン適応したい場合は多少工数をかけてでも手動で学習モデルをつくったほうがいいかもしれません。

IPAdic辞書形式(文字列長)

--output 5を指定すると文字列長に応じてコストが設定されたIPAdic形式の文字列が出力されます。

% echo "印刷用紙を複合機で印刷する。" | \
  docker run -v /var/lib/termextract:/var/lib/termextract \
  -a stdin -a stdout -a stderr -i naoa/termextract termextract_mecab.pl --output 5 
複合機,0,0,-14500,名詞,一般,*,*,*,*,複合機,*,*,ByTermExtractLen
印刷用紙,0,0,-16000,名詞,一般,*,*,*,*,印刷用紙,*,*,ByTermExtractLen

これを利用すれば、プレーンテキストを入力するだけで、用語の文字列長に応じてコストが極端に低くなるように設定されたIPAdic辞書を簡単に追加することができます。

この場合、ほぼ既存の形態素解析辞書のコストよりも低くなるため、文脈によらず追加した用語が優先的に切りだされるようになります。

なお、この方法はすでに存在する用語を押しのけて切り出されるようになるので、短い用語や一般的な用語を追加するのはお勧めできません。

テキストマイニング系では多少の誤りは統計的に淘汰されることにより影響が低いと思われますので、多少ノイズがあっても専門用語を多数追加したほうがよい結果が得られるかもしれません。

IPAdic辞書形式(複合語抽出なし)

--no_term_extractを指定すると形態素解析、専門用語抽出をせずにMeCabで自動コスト推定したIPAdic形式の文字列が出力されます。

% echo "印刷用紙" | docker run -v /var/lib/termextract:/var/lib/termextract \
  -a stdin -a stdout -a stderr -i naoa/termextract termextract_mecab.pl --no_term_extract
印刷用紙,1285,1285,7336,名詞,一般,*,*,*,*,印刷用紙,*,*,ByMeCabEst

その他のオプション

その他、出力件数や重要度の閾値等を設定することができます。TermExtractのサンプルスクリプトにある設定項目はほぼすべてコマンドオプションにマッピングしています。 詳しくは、GitHubを参考にしてください。

MeCab辞書への追加

形態素解析速度を損なわないように、システム辞書へ追加することをおすすめします。

システム辞書への追加は、辞書ソースフォルダに辞書形式のテキストファイルを設置して再ビルドします。 なお、追加辞書ファイルの文字コードに注意です。このDockerの環境では、utf-8でテキストが書き出されるのでeuc-jpに戻す必要があります。

自動コスト推定した辞書の追加例

% docker run -v /var/lib/termextract:/var/lib/termextract -i -t naoa/termextract /bin/bash
% echo "印刷用紙を複合機で印刷する。" | termextract_mecab.pl --output 4 > /mecab-ipadic-2.7.0-20070801/user.csv
% cd /mecab-ipadic-2.7.0-20070801
% nkf -e --overwrite user.csv
% make clean
% ./configure --with-charset=utf8; make; make install
# echo "印刷用紙を複合機で印刷する。" | mecab
印刷用紙        名詞,一般,*,*,*,*,印刷用紙,*,*,ByTermExtractEst
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
複合    名詞,サ変接続,*,*,*,*,複合,フクゴウ,フクゴー
機      名詞,接尾,一般,*,*,*,機,キ,キ
で      助詞,格助詞,一般,*,*,*,で,デ,デ
印刷    名詞,サ変接続,*,*,*,*,印刷,インサツ,インサツ
する    動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
。      記号,句点,*,*,*,*,。,。,。
EOS

「印刷用紙」と「複合機」を追加していますが、「複合機」では分割されませんでしたね。MeCabの自動コスト推定の結果によって設定されたコストでは、この文脈では分割されませんでした。この文脈で正しく分割して欲しい場合は、正解の形態素解析結果を作って再学習させる必要があります。

文字列長に応じた低コスト辞書の追加例

% docker run -v /var/lib/termextract:/var/lib/termextract -i -t naoa/termextract /bin/bash
% echo "印刷用紙を複合機で印刷する。" | termextract_mecab.pl --output 5 > /mecab-ipadic-2.7.0-20070801/user.csv
% cd /mecab-ipadic-2.7.0-20070801
% nkf -e --overwrite user.csv
% make clean
% ./configure --with-charset=utf8; make; make install
% echo "印刷用紙を複合機で印刷する。" | mecab
印刷用紙        名詞,一般,*,*,*,*,印刷用紙,*,*,ByTermExtractLen
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
複合機  名詞,一般,*,*,*,*,複合機,*,*,ByTermExtractLen
で      接続詞,*,*,*,*,*,で,デ,デ
印刷    名詞,サ変接続,*,*,*,*,印刷,インサツ,インサツ
する    動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
。      記号,句点,*,*,*,*,。,。,。
EOS

こうすると、「印刷用紙」、「複合機」ともに優先して分割されるようになります。 ただし、この方法は、短い用語や一般的な用語が追加されないように注意した方がいいと思います。

Wikipediaでの用語抽出例

Wikipediaからオープンソースのカテゴリを持つページを抽出したテキストファイル6.4MBからTermExtractにより専門用語を抽出してみます。

なお、Wikipediaからのカテゴリを持つページの抽出は、以前、全文検索エンジンGroongaのRubyバインディングRroongaを使ったベンチマークプログラムで作成したデータベースから抽出しました。

% time cat example/open_source.txt | docker run -v /var/lib/termextract:/var/lib/termextract -a stdin -a stdout -a stderr -i naoa/termextract termextract_mecab.pl
real    0m57.540s
user    0m0.015s
sys     0m0.020s

解析結果の上位100位は以下の通りです。全データは、こちらから参照することができます。

% head -100 open_source_words.txt
オープンソース               3271565.53
ソースコード                  1148379.84
Linux                      1145244.41
Windows                              719143.07
フリーソフトウェア          528618.23
ファイルシステム             330097.36
プラグイン                      231639.42
Java                          224278.60
公式サイト                      178292.62
ソースファイル                119766.41
Linuxカーネル                    108254.88
ソフトウェア開発              99021.32
FreeBSD                       96416.05
Python                          85005.73
開発環境                          82837.95
BSDライセンス                    80794.42
設定ファイル                    79932.39
Webサイト                          76738.43
コンピュータシステム        71030.63
フレームワーク                 70935.05
Debian                       68897.67
コンピュータゲーム           68737.58
拡張機能                          66684.10
開発チーム                       64753.75
公式リリース                    62297.61
Unix系OS                             58288.22
Apache                           57019.52
Mozilla                          55182.90
処理系                             53580.87
Webシステム                       52866.46
Firefox                          50441.02
ファイル名                       49379.71
Webサーバ                          48128.29
管理画面                          46835.77
デスクトップ環境              46306.85
文字列                             44828.24
ゲーム機                          44209.68
Google                          44127.48
ファイル形式                    44066.47
開発プロジェクト              43722.48
仮想化                             42989.77
ゲームエンジン                 42329.06
ウェブブラウザ                 41486.02
Perl                          41174.69
Webアプリケーション           40369.26
フリーソフト                    40277.61
Debianプロジェクト              40133.80
Play                          39835.14
Apacheソフトウェア財団        39716.86
webページ                          36313.45
国際化                             35435.52
GNOME                           32105.18
コードベース                    30556.86
Webページ                          30230.03
GNUプロジェクト                 30071.87
文字コード                       29706.67
バックエンド                    27899.38
プロジェクト管理              27781.24
画面開発                          27641.52
著作権                             26789.01
ブラウザ                          26203.04
Unix                            25665.32
機能拡張                          25403.47
UNIX                          24603.10
デスクトップ                    24601.07
リンクコンピュータ           24400.02
サブプロジェクト              24241.51
Ruby                           24157.42
BSD系OS                              23188.30
アドベンチャーゲーム        23091.86
コマンドライン                 22857.34
作曲家                             22567.23
ファイルフォーマット        22391.98
変更点                             22186.33
Linuxシステム                     21900.20
ベースシステム                 21424.94
Unix系                        20711.56
ゲームプログラミング        20629.42
HTML                        20533.24
暗号化                             20299.04
編集機能                          19913.35
エンコード                       19837.66
オープンソース実装           19693.71
FLOSS                        19645.75
Windows用ゲーム                   19281.47
初期化                             19231.87
計算ソフト                       19102.70
クライアント                    19063.37
Emacs                          19013.35
研究プロジェクト              18959.65
開発終了                          18501.36
標準ソフト                       18411.54
オープンソース化              18354.86
MySQL                          18147.87
日本語化                          18143.13
Cライブラリ                      18091.82
ウェブサイト                    17744.98
機能開発                          17733.23
ブログ                             17712.72
データソース                    17667.48

経験則的に正規表現でフィルタをかけたおかげもありますが、重要度の上位はそこそこ良い感じにとれているのではないでしょうか。 なお、重要度が低い部分は結構ノイズがおおかったりするので、適宜閾値等を調整したり取捨選択したりする必要があると思います。

同様に、Wikipediaからファミリーコンピュータ用ソフトのカテゴリを持つテキストファイル11MBからTermExtractにより専門用語を抽出してみます。

%  time cat example/famicon.txt | docker run -
v /var/lib/termextract:/var/lib/termextract -a stdin -a stdout -a stderr -i naoa
/termextract termextract_mecab.pl > famicon_words.txt

real    1m1.901s
user    0m0.022s
sys     0m0.042s

解析結果の上位100位は以下の通りです。全データは、こちらから参照することができます。

# head -100 famicon_words.txt
ゲームオーバー                225391.74
コンピュータゲーム          207293.26
アクションゲーム             191859.12
ゲームソフト                   173559.54
アーケードゲーム              82471.63
攻撃力                             78720.54
ゲームシステム                 76020.80
シューティングゲーム        58060.15
バーチャルコンソール        47166.23
ゲーム画面                       47020.95
敵キャラクター                 41591.97
難易度                             38140.79
野球ゲーム                       33310.86
ゲームクリア                    31195.55
ステージクリア                 30310.27
ファミコンソフト              28704.64
アドベンチャーゲーム        27880.07
ゲーム作品                       25405.97
ゲーム機                          24178.18
ボスキャラクター              22827.36
ゲーム内容                       22718.59
ゲームモード                    22519.06
ボス戦                             19458.30
Aボタン                            19204.68
ボーナスステージ              18773.07
家庭用ゲーム機                 18195.87
プレイ                             16706.88
タイトル画面                    16570.34
残機                           14833.45
シリーズ作品                    14581.82
敵機                           14208.63
敵キャラ                          13983.64
戦闘機                             12714.64
Bボタン                            12165.97
ニンテンドーDS                  11585.81
ゲーム開始                       11576.77
ゲーム雑誌                       11135.99
パズルゲーム                    11131.51
ゲームシリーズ                 10931.45
ゲームボーイ                    10911.38
専用ソフト                       10823.23
キャラクターゲーム           10125.81
テレビゲーム                     9729.73
ゲームオリジナル               9713.91
ゲームブック                     8578.78
ボスキャラ                        8438.66
アクションゲーム画面         8421.34
敵弾                         8256.72
登場キャラクター               8193.54
攻撃アイテム                     8107.03
防御力                              7834.61
ゲーム終了                        7511.86
ファミリートレーナー         7510.19
ボス敵                              7395.66
攻略本                              7162.74
登場人物                           7125.86
戦闘力                              7112.11
仕事カード                        6867.87
ボスキャラクターボス         6849.71
攻撃ボタン                        6795.73
ゲームデザイン                  6549.28
ジャンプ力                        6441.60
ゲームデータ                     6272.59
パックマン                        6256.40
マリオシリーズ                  6251.48
守備力                              5980.39
ゲームソフトナムコ            5954.83
ファミコン用ソフト            5871.01
ゲームソフトサン電子         5733.77
移植作品                           5698.47
ゲームスタート                  5677.25
人同時プレイ                     5628.80
ナムコゲーム                     5594.78
体当たり                           5571.98
獣人                           5546.24
アクションステージ            5507.70
ハゲ丸                              5492.77
障害物                              5465.10
シリーズ作                        5406.64
ステージ構成                     5246.22
変更点                              5239.89
ステージ開始                     5236.79
スタートボタン                  5235.63
ゲームバランス                  5186.70
キャラクターデザイン         5149.77
ゲーム化                           5125.85
人対戦                              5061.89
赤影                            4954.96
対戦相手                           4934.96
PCゲーム                            4851.10
PCエンジン                         4830.22
ゲーム発売                        4825.91
ゲームソフトセガ               4792.47
マップ画面                        4769.02
リメイク                           4753.66
ボーナス点                        4691.56
攻撃方法                           4580.24
ステージボス                     4379.08
PC用ソフト                         4378.88
宝箱                             4226.46

「ゲームソフトセガ」、「ゲームソフトナムコ」、「ボスキャラクターボス」などあまり正しくない結合のされ方も含まれていますが、ある程度はそれらしい用語も抽出できていますね。 他のオプションを組み合わせたり学習情報によっては、うまく解析できるようになるかもしれません。

おわりに

このような一時的な解析環境の構築は一度やった後は、結構忘れがちなのでDockerで環境を作っておくと便利だなぁと思いました。

文書構造的に容易に抽出可能なタイトルやキーワードなどから固有名詞を抽出する方法が知られています。 たとえば、Wikipediaのタイトルやはてなキーワードなどがよく知られていますね。

よりキーワードを集めたい方は、TermExtractを使ったキーワード抽出を試してみるといいのではないのでしょうか。

最近は、word2vecなどに興味がある人が多いと思いますが、学習の前には用語を抽出して辞書に追加した方が面白い結果が得られると思いますよ。

word2vecや連想検索エンジンGETAssocのDockerファイルも近日中に作ろうと思っています。

7/14 記事を追加しました。

word2vecとプレーンテキストをフィルタや正規化をしつつ分かち書きしてくれるstring-splitterコマンドとベクトルを自由に足し引き演算(+-)できるようにしたword2vec-calcコマンドをDockerファイルdocker-word2vecで簡単に使えるようにしました。また、アナロジー以外のベクトル演算をした実験結果を紹介しています。

word2vecをDockerでプレーンテキストから簡単に使えるようにしました