GENIA taggerを使うクラスの見直し

 GENIA taggerC++で書かれた英文品詞解析ソフトですが、これをRubyで呼び出すため、今まではサーバプログラムとして起動していましたが、今回はこれを書き換えました。
 いちいち別プログラムとして起動してから、本命のRubyコードを走らせるのも面倒だし、ソケットを介すことになるので並列化して使用することができないので、今回はGENIAをRubyプログラムの子プロセスとして起動することを考えました。

 具体的には、GENIAの制御用Rubyクラスを作り、そのコンストラクタで子プロセスを起動しGENIAを実行するようにしました。後はクラスのメソッドに、英文を受取ってGENIAに渡し、解析結果をreturnするものを用意しました。

class GENIA_controller
def initialize(genia_path)
@genia = IO.popen("cd "+ genia_path +" ; ./geniatagger 2>/dev/null", "r+")
end

 詳細は私のGitHubの方にあります。
 これでより簡単にGENIAを使用することができるようになり、品詞解析の並列化にも対応できます。またこのクラスが破棄されるまで子プロセスは残り続けるので、GENIAを再起動することなく、次々に英文解析を行っていくことができます。
 次回はこれを使って英文解析結果をマージする部分を作っていこうと思います。

英文の単語出現頻度を計算するクラスの続き

 前回に引き続き、英文から名詞を抜き出すRubyクラスの実装を行いました。
 前回は英文の単語数で分類するところまで書いたので、今回は分類された英文ごとに、品詞解析にかけて名詞を抜き出し、その出現数をカウントするところを実装しました。
 品詞解析はGENIA taggerを使用しているので、これを別プロセスで起動していることを前提に、そのポートに英文を投げるというように書きました。あとは「NN」というタグが名詞を表しているので、そのタグがついた単語を回収するように書きました。

@socket.puts @original_hash[id].gsub("\n", " ")
result = @socket.gets.gsub(" ", "\n").chomp

result.each_line do |line|
elements = line.split(/\t/) #タブ区切り

if elements[2] =~ /^NN/ #名詞を回収
word = elements[1].downcase #小文字に直す

if word_list.include?(word) #既に追加済なら
word_list[word] += 1
else #新規登録
word_list[word] = 1
end
end
end

 分類された英文ごとに結果をファイルに出力するメソッドも用意して完成したので、私のGitHubの方にアップしてあります。

 そして書いていて気づいたのですが、GENIA taggerをわざわざサーバプログラムとして起動する必要もなく、品詞解析を行うときに起動すれば良いように思ったので、品詞解析を行うメソッドを集めたクラス「GENIA_controller」を作成しています。
 今回は英文1分だけを解析できるところまで作成したので、次回複数行に対応させて使用できる形にしたいと思います。

英文から名詞を取り出し出現頻度を計算するクラス

 英文の特徴抽出を行う際に、以前実装した英文から名詞を取り出す部分を、今回1つのクラスとしてまとめることにしました。
 名詞の判定にはGENIA taggerを使用していて、これを別プロセスで起動し、ソケット通信でRubyスクリプト中で解析したい英文を送るようにしています。今まではこのGENIA taggerプログラムを、手動で別に走らせるRubyスクリプトを使っていましたが、二度手間で面倒なので、今回これもまとめることにしました。

 指定の英文リストから、名詞を取り出し出現頻度を計算するRubyクラス、WordCountを作成しています。現在英文リストを分類し、外部プロセスからGENIA taggerを起動するところまで実装しました。
 途中経過ですが、GitHubにて公開しています。順次中身の実装を進めていこうと思っております。

PubMed APIを利用して、クエリから関連著者リストを作成

 前回に続き、著者リストを作成するRubyスクリプトを書いています。今回は、検索ワードをクエリとしてPubMed APIにアクセスし、関連論文リストから著者名を抜き出し、全著者名の出現頻度を計算するところまで完成させました。

 まず、検索ワードにヒットした論文を返却されるとき、PubMed APIのほうに最大いくつまで返すかという設定ができるので、これを利用して取得数を制御できるようにしました。PubMedのマニュアルページ(E-utilities Quick Start)を参照したところ、URLに「&retmax=」を追加すればOKでした。

api += '&retmax=' + @maxIDs.to_s #取得最大ID数を設定
xml = open(api, 'User-Agent' => 'ruby').read

として、取得数を変えられることを確認しました。100件を一気に取得することもできました。
 次に、取得したXMLから各論文の著者名を抜き出し、数を数えるところを実装しました。XMLのなかで「Article/AuthorList/Author」の中の、「LastName」と「ForeName」を回収すればOKでした。
 ただし、LastNameがなかったりすることがあったので、存在するかを確認してから回収するようにしました。

if author_part.elements['LastName'] #フィールドが存在するなら
last_name = author_part.elements['LastName'].text
else
next #無視して次へ
end

if author_part.elements['ForeName'] #フィールドが存在するなら
fore_name = author_part.elements['ForeName'].text
else
fore_name = "" #存在しなければ空配列
end

 あとは、これをハッシュテーブルに登録し、既にハッシュに存在するなら出現数を+=1するようにしました。
 試しに100件論文を取得し、ハッシュテーブルを作成してファイルに書き出してみたところ、全筆者705名が回収できました。そのうち2回以上出現した筆者は36人程度でした。また、やはり筆者名の表記揺れがあるようで、ForeNameがイニシャルな場合とフルネームの場合で、おそらく同一の筆者が別々になってしまっていました。このあたりはまだ改善の余地がありますので、次回以降見直していきたいと思います。

PubMedで検索した論文一覧から筆者の出現頻度リストを作る

 前回までで、筆者ごとにまとめられた単語リストから、研究トピックと筆者のネットワーク図を作ることができるようになりました。なので、そのプログラムを使って何ができるかを試すため、簡単な応用先を考えることにしました。
 そこで、自分の研究に近いことをやっている人を探すために、PubMedなどで検索ワードを与えて、出てきた論文の筆者と内容を確認する、という作業を自動化することを考えました。筆者のリストは出現頻度から作成し、その筆者の論文内容をトピック解析することで、内容を可視化していく、という構想を立てています。
 作るプログラムとして具体的には、まず使用者からの検索クエリを受け付け、そのワードでPubMed APIをたたいて論文ID一覧を手に入れます。このとき、検索クエリをMesh wordsに当てて、該当するMesh wordsでAPIをたたくようにすると、より精度が良くなるかと思っています。
 次に、論文ID一覧から論文著者一覧のxmlを得て、パースして著者の出現頻度を計算します。そして、出現頻度の高い筆者について、論文のAbstractから単語を抽出し、トピック解析→ネットワーク図作成、という前回までの流れにのせようと思っています。

 今回は、まずAPIをたたくRubyスクリプトを書くところから入りました。前に作ったAPI操作用のクラスがあったので、これをリファクタリングしつつ、クエリから著者一覧が得られるところまでできました。次回は、著者の出現頻度リストを作成するところから入っていこうと思っています。

グラフ作成クラスの公開

 前回に続き、今回はトピック解析が終了して出力されるthetaファイルを元に、文章のネットワーク図を作成する「TopicGraph」クラスを修正し、GitHubにて公開しました。
 このクラスはThetaファイルを読込んで、各文章のトピックへの分類確率に基づいて、ネットワーク図を作成し出力します。クラスをnewする段階でthetaファイルをパースし、その後make_graphメソッドを呼び出すとグラフファイルが出力されます。
 以前の実装では、トピック数は5個までだったので、色はGraphvizのBrewer Schemeで足りていたのですが、今回からはトピック数がもっと多い場合も想定するので、色指定をRGBで書き込むようにしました。
 参考になりそうなパステルカラーを探して、http://kohrin.net/color/color.htmlのサイト様で公開されている色を記述しました。 TopicGraph.rbには8パターンまで用意しましたが、もっと必要な場合は追加することができます。

 これで文章の単語リストからグラフを出力するところまで、まとめることができました。次回からは、これらのクラスの使い方を紹介する意味も込めて、多くの文章をトピック分類する手法を、階層的に実行するところまで含めて試してみたいと思っています。

トピック解析後の有効トピック数決定のメソッド

 前回に引き続き、「AuthorTopicExplorer」クラスの実装を行いました。
 今回は実装したRubyクラスの実行動作確認も行い、軽くデバッグしました。RubyでLDAプログラムを起動するのは始めてでしたが、system()命令で実行でき、読込ませた単語リストファイルがあるディレクトリに、トピック解析の結果ファイルが出力されることを確認しました。
 また、前回途中だった「トピック数ごとに分類確率がn%以上の文章数が、全体の何%になるか」を調べるメソッドを実装しました。分類確率ごとの累積度数やトピック内の文章数を、ファイルに出力する部分は残しつつ、上記の条件にあった設定トピック数のなかで、最大のトピック数を返却するように実装しました。
 
 以上を持って、トピック解析に必要な計算のまとめは完了したので、作成したRubyクラスをGitHubにて公開しました。私のGitHubのページにて公開しております。
 次回は、トピック解析の結果からグラフを作成するところをまとめていこうと思っております。