2016年5月4日水曜日

Rでtwitterの検索結果から同表記異義語をフィルタする その3 集計とRStudio Projectファイル

この記事はRでtwitterの検索結果から同表記異義語をフィルタする その2 Wikipediaの記事抽出のつづきです。

対象となる文書が集められたら、あとは集計するのみ。

各クラスを特徴づける語彙のスコアを算出する

RMeCabパッケージの docMatrix 関数を使用した。想像以上に簡単。

tf_idf <- docMatrix(WIKIPEDIA_CONTENT_DIR, weight="tf*idf")

データフレームから関心のない列を取り除く

Rの intersect(arg1, arg2) 関数を使い、arg1arg2双方に存在する文字列を名前にもつ列だけを取り出す。

tf_idf <- tf_idf[,intersect(colnames(tf_idf),kTargetClasses)]

データフレームにおいて特定の行名を持つ列のデータを操作する

tf_idf[Term=target_word,] <- (tf_idf[Term=target_word,] * 0)

結果

そのクラスに所属する確度(全クラスのスコアの合計で正規化した値)に対しヒューリスティックに設定した値(0.27)でフィルタリングした結果。検索結果に含まれるツイートを一つ一つ人手で分類するよりかは生産性が高そう。

GitHubで公開したRStudio Projectファイルについて

今回作成したRファイルをGitHubで公開しました。
twitter-word-sense-disambiguation-w-tf-idf-of-wikipedia
constants.Rファイルを編集すると、お好きなキーワードで試すことができます。使い方についてはREADME.mdファイルとこの連載記事(初回)を参考にしてください。

課題

  • Wikipediaに記事がない地味に有名な固有名詞は識別することができない。
  • 抽出したい意味が、他の同表記語と比べて明らかに違う分類(例:抽出対象は地名で、他の同表記語は人名など)である場合、格フレームを活用した分類も有効に働くのではないか。

備忘

  • Rのapply関数便利。cbind等でテーブルを作ろうとすると、matrixができあがる。matrixだと複数のデータタイプを持たせるのに向いてない(numericだったmatrixに文字列から構成されるmatrixをcbindすると、numericだったデータがfactor型になって不等号を使用したフィルタリングができなくなる)
  • 1行のみのデータに対しapplyを掛けたいときはlapply関数(list-apply?)を使用する。applyを使おうとすると次元数が足りないというエラーが出力されて止まる。

2016年5月3日火曜日

Rでtwitterの検索結果から同表記異義語をフィルタする その2 Wikipediaの記事抽出

この記事はRでtwitterの検索結果から同表記異義語をフィルタする その1のつづきです。

RでWikipediaの記事を抽出する

WikipediR という便利なRパッケージがあったため、それを使う。WikipediR が提供する text というプロパティを使うと、Wikipediaの記事のヘッダやサイドバーを取り除いたHTMLが簡単に取得できるので便利。

それでも text が返却する文字には<a></a>の様なタグが含まれ、文章が途切れるので、xml2 パッケージを使い、テキストのみを抽出した。

この後、RMeCabパッケージを使い、各記事に書かれた文書の特徴となる語彙リスト(tf-idf)を作成するが、この作業では対象となる文書をファイルで指定する必要があるため、変数texts に記憶されたデータをファイルに書き出した。

install.packages("WikipediR")
install.packages("xml2")

library(WikipediR)
library(xml2)

page_name <- "小笠原諸島"

wp_html <- page_content("ja", "wikipedia", page_name=page_name)
# page_content関数は独自のpccontentクラスを返すため、
# その中のparse->text->"*"プロパティを明示しxml2ライブラリに文字列を渡す
tree <- read_html(wp_html$parse$text$"*", encoding="UTF-8")
content_text <- xml_find_all(tree, "//body//text()")
# content_text はxmlnode型のリストなので、テキストに変換する
# (xml2パッケージが提供するxml_text関数を使用)
texts <- sapply(content_text, xml_text)
# 改行のみ含まれる要素を削除する
texts <- texts[texts != "\n"]

# 保存先パスを生成する
file_path_and_name = file.path(WIKIPEDIA_CONTENT_DIR,
                                       # 保存先ファイル名
                                       paste(page_name, ".txt", sep=""))
# ファイルに保存する
write.table(texts, file=file_path_and_name, row.names=FALSE, quote=FALSE)

備忘

  • 最初はWikipediRを使わず、Wikimediaが提供する記事一覧のアーカイブ(ここの jawiki-latest-pages-articles.xml.bz2)をダウンロードし、それを使用する予定であったが、Wiki文法を取り除き平文にするシンプルな方法がみつからなかった。
  • 最終的にファイルに書き出すのであれば、ここの部分だけpythonなどで書いたほうが早かった気がする。

RでWikipediaの記事をランダムに抽出する

扱う文書量が少ない場合、一般的な名詞、たとえば「りんご」がたまたまクラスAの文書だけに出現していると、たとえ「りんご」とクラスAとの関連が弱い場合でも「りんご」が出現するツイートはクラスAに重み付けされて評価されてしまう。

こういった事態を避けるため、収集する文書を増やし、各クラスに含まれる一般的な語彙はなるべく打ち消されるようにした(tf-idf)。

WikipediRはランダムにWikipediaの記事を取得する random_page という関数を提供しており、これを利用した。はじめ namespace 引数の指定を省略して実行すると、Wikipediaの改版履歴など意図とは異なるページも取得したため、Built-in namespaces を参考に、記事(0)のみを指定するようにした。

wp_html <- random_page("ja", "wikipedia", 
           # 記事のみを対象とする(会話ノートやテンプレートページを含めない)
           namespaces = list(0))

Rでtwitterの検索結果から同表記異義語をフィルタする その3 集計とRStudio Projectファイルに続きます。

Rでtwitterの検索結果から同表記異義語をフィルタする その1

背景

twitterにおいて検索キーワードを指定し、そのキーワードを含むツイート一覧結果を受け取っても、違う意味の言葉が入ってくる。たとえば、検索したい人物を指し示す固有名詞を入力しても、同じ名字を持つ他の人物や、地名もヒットしてしまう。なんとかして固有名詞を更に詳細に区分できないだろうか。

今回は、東京都の小笠原に関するツイート調べるつもりで「小笠原」で検索した場合、野球やサッカーの小笠原選手に関するツイートもヒットしてしまう問題を取り扱い、小笠原選手に関するツイートを取り除く方法を考察する。

方針

(検証中)Wikipediaの記事を使い、東京都の小笠原と一緒に出現しやすい語彙一覧、野球の小笠原選手と一緒に出現しやすい語彙一覧、サッカーの小笠原選手と一緒に出現しやすい語彙一覧をそれぞれ作成する。

その後「小笠原」を含むツイートにて、そのツイート内の語彙から、どの小笠原に所属するツイートかを判定する。

自然言語処理の分野において、この手のタスクは曖昧語義性解消(Word Sense Disambiguation)と呼ばれる。Wikipediaを用いたアルゴリズムも既にいくつか発表されてるようだが、一方である書籍によれば「(意味解析は)実用レベルの性能には達しておらず,フリーのツールというものもいまのところ存在しない1」と記され、実際すぐに使えるツールというのもないようだ。
1奥村 2010 p.81

ツール

PythonでもRでも達成できそうで、どちらを使うか迷ったが、今後個人的にRを使う予定があるので勉強の意味も兼ねRを採用した。

手順

twitteRのセットアップ

フィルタリング対象となるツイートを収集するため、パッケージを利用する。

install.packages("twitterR")
Warning in install.packages :
  package ‘twitterR’ is not available (for R version 3.2.4)

早速twitterのデータ取得に使うライブラリが利用不可のようで、あせる。 問題は単純で、パッケージ名は "twitter R" ではなく "twitteR" 。

Setting up the Twitter R package for text analytics | R-bloggers を参考にtwitter appを新規作成し、そのappのconsumer keyなどを setup_twitter_oauth 関数を使い twitteR に設定。下記コマンドでツイートが収集できることを確認した。

searchTwitter("小笠原")

Rでtwitterの検索結果から同表記異義語をフィルタする その2 Wikipediaの記事抽出に続きます。

今回使用したRファイルをGitHubで公開しました。その3 集計とRStudio Projectファイル

参考書籍

2016年1月3日日曜日

再帰型ニューラルネットの一種、LSTMをsynaptic.jsで試す

再帰型ニューラルネット

再帰型ニューラルネットは回帰(型)ニューラルネット、あるいは循環ニューラルネットと訳されることもあるがどちらも同じもの1。再帰型ニューラルネットワークとは、内部に閉路をもつニューラルネットの総称2

1岡谷 2015 p.112
2岡谷 2015 p.114

synaptic.js

synaptic.jsはアーキテクチャによらないJavaScriptのnode.jsおよびブラウザ向けのライブラリ。
今回はDemoとして公開されている下記Discrete Sequence Recallを試す。

Discrete Sequence Recall (処理に時間が掛かるためPCブラウザでの閲覧を推奨)

このデモでは入力として色で分けられた●からなるSequenceを受け取り、灰色、黒色●(いずれもPromptsクラス)を受け取った時に水色と緑色(Targets)を、Sequence内の順番通りに出力する。Sequenceの中には、Targets、Promptsいずれにも含まれないDistractors()が含まれる。このネットワークはどれがTargetsか、Promptsか、Distractorsかを事前に知らない。

var LSTM = new Architect.LSTM(6,7,2);
LSTM.trainer.DSR({  
    targets: [2,4],  
    distractors: [3,5],  
    prompts: [0,1], 
    length: 10 
});

Architest.LSTM

ソースコード
Synaptic.jsが提供するLayerオブジェクトを活用し、ネットワークの構築が下記の様に行われる。peepholesが何を意味しているのかは不明。
architest.js 90行目-159行目
architest.js 165行目-173行目
165行目以降で新たに作成するTrainerオブジェクトのプロパティ値を用意する。new Trainer()の第一引数として指定された値は、Trainerのnetworkプロパティとなる。

Trainer.DSR

ソースコード
iterationの値(規定値:100000)の数だけ、シーケンスの作成、訓練を行う。

"TRY ANOTHER SEQUENCE"ボタンをクリックした時の挙動

ソースコード

validate関数が呼び出される。その後一連の手続きを経て(next関数に入る)新たなinput配列が生成され、それを引数として LSTM.activateが呼び出される。LSTM.activateはpredictionを返却し、このpredictionを引数としvalue関数を呼び出すと、その戻り値としてLSTMの出力が何番目のTargetsに当たるのかが得られる(Targetの出力がない場合はvalue関数の戻り値が"none"となる)。
next関数はinput, output行を出力する度に呼び出される。そのためnext関数内で実行されるLSTM.activateもその分だけ呼び出しを受ける。

参考書籍

  • 岡谷貴之(2015)『深層学習 』(機械学習プロフェッショナルシリーズ)講談社