LDAで日本語PDF分析
概要
最近、LDAを(pythonで)実装する機会がありました。
サンプリングを用いる実装だったので、Python等のスクリプト言語だとどうしても計算時間が問題になってしまいます(特に大規模なデータに対して)。
せっかくなのでコンパイル系の言語であるJavaで実装し直し、ついでに日本語PDFファイル(というか日本語論文)をLDAで分析してみました。
全体的な手順としては、
となっています。
分析に使ったLDAの実装やスクリプトはGithubにあります。
LDAのJava実装
https://github.com/breakbee/LDA4J
PDF分析のスクリプト
https://github.com/breakbee/PDFAnalysis
を使用しました。
LDA
LDA(Latent Dirichlet Allocation)は、簡単に言うと自然言語処理における確率的なクラスタリング手法です。クラスタのことを「トピック」と読んでいます。
ある文書 の 番目の単語がトピック に属する、という形でクラスタリングします。
例えば、トピック 0 には「ホームラン ヒット スクイズ」など野球に関する単語が、トピック 1 には「ワールドカップ 得点王 オーバーヘッド」などサッカーに関する単語が頻出する、という結果が得られます。
どのトピックが選ばれるかについての確率(トピック分布の確率)と、そのトピック内での単語の選ばれやすさ(単語分布の確率)があり、それを見ることによって分析の概略を掴むことができます。
参考
Latent Dirichlet Allocation ゆるふわ入門 - あらびき日記
Latent Dirichlet Allocations の Python 実装 - Mi manca qualche giovedi`?
Latent Dirichlet Allocation(LDA)を用いたニュース記事の分類 | SmartNews開発者ブログ
PDFからテキスト抽出
PDFファイルからテキストを抽出するのに、Apache PDFBox というライブラリを使用しました。
Apache PDFBox
https://pdfbox.apache.org/
使用方法はこんな感じです(公式より)。
java -jar pdfbox-app-x.y.z.jar ExtractText [OPTIONS] <inputfile> [Text file]
参考
https://pdfbox.apache.org/commandline/#extractText
楽にテキストを抽出できますが結構エラー吐きます。
また、出力されたテキストはPDFでの改行位置で文章が途切れているので、そこらへんをうまく処理する必要があるかと思います。
分析
テキスト抽出後、一度整形し、日本語のみを抽出し、形態素解析し、名詞だけをとりだして特徴量とし、LDAで分析します。
自分ではこんな感じで実験してみました。
- 主に機械学習関係の論文とスライドを462ファイル用意
- 特徴抽出前のPDFファイルは合計約628MB
- 特徴抽出後のテキストファイルは約3.7MB
- LDAのトピック数は100、サンプリング回数は10000回
- 学習はおよそ26時間
実験結果はこんな感じになりました。
トピック分布の確率(のパラメータ)が0.1以上のトピックについて、頻出単語上位10個を表示しました。
Summarization: Topic num = 100 print Topic if theta > 0.1 and 10 frequent words in Topic Topic : 11 (theta = 0.5105679678472282) 確率 : 0.025439009730502445 モデル : 0.022912977793661367 分布 : 0.02147939375233516 データ : 0.01885995548985526 学習 : 0.01504654071703569 推定 : 0.014226189509251287 関数 : 0.012995662697574684 計算 : 0.009730502444809046 問題 : 0.009628973829984244 アルゴリズム : 0.007346610568722689 状態 : 0.007196348218781981 Topic : 51 (theta = 0.12858576604531036) 利用 : 0.025817941788200714 評価 : 0.020462555889056332 推薦 : 0.018718941875381416 情報 : 0.017971678726663595 アイテム : 0.015729889280510133 システム : 0.01372473316478398 データ : 0.012255115638972264 ユーザ : 0.010598682325981094 嗜好 : 0.007958352533844793 検索 : 0.007385450786494464 予測 : 0.005903378874870786 Topic : 77 (theta = 0.1504352870224158) 言語 : 0.0222420226095673 表現 : 0.016327894414434482 意味 : 0.01551484100907724 単語 : 0.015069332293812998 パターン : 0.01056969426964415 処理 : 0.010001670657682241 翻訳 : 0.008453527872138999 構造 : 0.007807540235005847 解析 : 0.007729576209834605 概念 : 0.007328618366096787 参照 : 0.0066492175753188176 LDA completed.
今回用意した論文は半分くらいは統計的機械学習について、あとは自然言語処理、データマイニング、ニューラルネットワーク等となっています。
Topic : 11 は統計的機械学習に、Topic : 51 はデータマイニング(特に推薦)、Topic : 77 は自然言語処理に対応していると考えられます。
表示されてはいませんが、ニューラルネットワークに対応するトピックもあったので、用意したPDFファイルの傾向を掴めていると言っていいのではないかと思います。
実際には、自分の持っているPDFファイルを適当に突っ込んだので、分析結果が出たあとに何となく眺めてみて「確かにこんな感じだなー」と思いました。
感想
- 分析結果をどう活用するか
今回は分析して結果を見ただけですが、実際の分析結果を用いて、自分の興味のありそうな未読論文を推薦してくれるシステムとかが作れるかもしれません(Google Scholar のマイライブラリ等が使えそう?)。
- プログラミング言語の使い分け
今回の試みとして、テキストの整形等はPythonやシェルスクリプト、計算の重い部分はJava、と役割分担をしてみました。
Javaでの機械学習の実装は面倒でしたが、Pythonでの実装より大幅に高速化されているのを確認しました(少なくとも倍近く)。
今回は26時間とかなりかかっていますが、サンプリング回数とトピック数が多いためであり、特にトピック数を減らせば計算時間が大幅に減らせます。トピック数が一桁だと数秒から数分でした(まあトピック数なんて事前にわからないんですけれども...)。
サンプリング回数はできるだけ多い方が良いと思います(本当はburn-inとかやらなきゃいけないんですがやってないです...)。
また、Javaに比べて手軽な処理やテキスト整形等はスクリプト言語であるPythonが便利でした。
結論として、前処理や特徴抽出に関しては、スクリプト言語で手軽に行うのが楽で良いと思います。
また、機械学習の手法に関しては、PythonやMatlab、Rで実装してみて、精度や計算時間を考慮してからC++やJavaで実装し直すのが良いのかな、と思いました。
- データが大事
今回一番実感したのは、データの収集方法と、前処理、特徴抽出の大変さです。
PDFファイルからのテキスト抽出は結構ノイズが入るので、前処理でしくじると結果も悲惨なことになりました。正規表現やユニコードなど色々と勉強し直しました。
特徴抽出も、最初は全単語を用いていたのですが、収拾がつかなくなってしまったので、用いる品詞を限定することにしました。
今まで私は分析手法ばかりに目が行っていたのですが、データの収集や前処理、実験結果の分析なども同じ位大切ということだと思います。
そして分析手法とは違いあまり定式化されていないので、自分なりのアプローチを確立し、問題ごとに良く考える必要があると感じました。