にほんごのれんしゅう

日本語として伝えるための訓練を兼ねたテクログ

Doc2vecを利用したレコメンデーションシステム

Doc2vecを利用したレコメンデーションシステム(は、諦めて盗用チェックツールとかのほうがいいかも)

Embeddingという文字、文字列をベクトル化する技術が機械学習、Deep Learning界隈で用いられているように見えます
CNNよるセンチメント分析や、Word2Vec、Doc(Paragraph)2Vecなどで用いられています
Doc2Vecとはドキュメントをベクトル化することで、足し算・引き算・コサイン類似度などを計算できるようにしたものです。ベクトル空間で表現されるので、何かと計算しやすく様々なアイディアが試されています。
Doc2VecはBag of wordsなどと異なり、一部のdmpvなどの実装においては単語の語順などの文法情報を保存することができます。この特性を利用して、センチメント分析を行うこともあるようです[1]。

モチベーション

Kindleなどで読んだ本に近い内容・コメントを持つ本を抽出したい

 リコメンデーション技術を広告以外の用途、とくに自分のインターネット生活のQoLを上げるために用いたいというモチベーションがあります。Kindleの本を多数購入して読んでいたり、また第三者に公開するKindle本の検索サービスを作っていることもあり、リコメンデーションの仕組みが必要だと感じました。

既存技術との比較検討

 初期の段階では、従来からの手法である、TFIDFなどの計算方法を用いようと思っていたのですが、文脈やなんやらに対してロバストでないとの批判記事を多く見たので、新しい方法がないかと模索していたところ、Doc2Vecの技術がわかりやすく応用しやすそうであるため、検討に入りました。同等の技術としてLDAなどがあります[2]。
f:id:catindog:20160824162841p:plain
 図.1 ユーザのツイッターの発言からMeetup.comなどとのニュース・イベントの適合率Precision-Recall曲線
 LDAに比べてDoc2Vecは大きな成果を上げていないように見えます。しかしながら、この例は、ツイッターの発言からそのユーザがなんのニュース・イベントに興味を持っているかを、Meetup.comに投稿されているデータを正解データとして、PR曲線を描いたものであります。
 
 商品のレコメンドにおいてはどうなのでしょうか。奈良先端科学技術大学院大学において、楽天のデータを使ったDoc2Vecのテストを見つけることができました[3]。
f:id:catindog:20160824162900p:plain
 図. 2 商品情報のベクトル化と、類似とランキング
 商品情報をベクトル化する際に、Word2VecとDoc2Vecを使った比較検討です。この時、どのくらいのユーザが表示した商品ページが引けるとという問題設定です。以下の式でhit-rateなる数を定義しています。
f:id:catindog:20160824162910p:plain
 Number of hits: ユーザが過去に示した関連商品のページ
 n: 一般的なユーザの人数

 直感的にわかりにくいので、もしかしたら間違っているかもしれません。
item vector-basedとは、ユーザがある興味のある商品リストを持っていると仮定した場合に、商品リストをベクトル化し、コサイン類似度で商品を引き当てることのようです。item Similarityの結果よりは改善されているようですが、過去の興味のあるリストを持っていると仮定した場合は、なにをやってもスコアが改善するのは自明な気もしますがどうなのでしょうか。
f:id:catindog:20160824213004p:plain
         図. 3 様々な標品の検索方法の結果

 最初のarXivに投稿された論文と組み合わせて考えると、商品リストに対してLDAでレコメンドを行う場合、商品リストのコンテキスト情報を十分に持っている場合は引当素性の決定などに使えそうであります。逆に、商品リストと言いつつ、商品名と僅かな形態素しか含まないのであれば、クエリ拡張のような使い方を想定してDoc2Vecが使えるのではないかという発想になります。

GensimというPythonモジュール

 ありがたいことに、Word2Vec関連の機能や、Doc2Vec関連の機能はGensimというモジュールとしてまとまっており、ただ関数を叩くだけで結果が得られます。LDAの機能もあるようですが、今回は試しませんでした。また、リファレンスが貧弱で読んだまま実行しようとしても、オブジェクトが定義されていなかったり、関数名が別のものに置き換わってしまっていたりと少し不便でした。製品や商品として用いるならば適宜、再実装する必要があるでしょう[4]。
https://github.com/RaRe-Technologies/gensim

「小説家になろう」で著者を分類・判定してみる

 小説家になろうのコンテンツを利用してDoc2Vecで何かできないかと考えていたのですが、小説の一行や一段落を一つのドキュメントとして捉えても、内容的に似ることなんて殆ど無いので、似てるのか似てないのかちょっとわかりませんでした。人間の目で見ても判断できないとは、ある意味、人が判断できない要素を機械学習で判断可能であり、すでに人間を超えている機能を持っていると判断できることでもありますが、分かりにくいし定性的に評価できないのでちょっとネタ的に面白くないです。
 
 せっかくなので、なろうの作品を2作品を一つの文章に混ぜあわせて、ある文章の塊がどちらの著者の文章なのか分類ができるのではないか、という仮定を立てました。これは、著者によって単語をチョイスするセンス、文法の癖などをEmbeddingしてベクトル化することで近しい値になるのではないかと思ったためです。
 
 「無職転生」[5]のコンテンツと「人狼への転生」[6]を混ぜてDoc2Vecに学習させて、ある文章の塊に対して、類似度を計算するということを行いました。

実験1. 「無職転生」のある文章の塊に対して近い類似度を持つtop 10件を計算する

9/10件が仮定通り、同じ著者の文章の塊となりました。

INPUT : アリエル様にお金をもらったことは黙っていよう。 ルディ、そういうの気にしそうだから。 お酒を注いで、酒の肴も用意した。 よし、完璧だ。 ええと、薬はもうちょっと後にするって作戦だったっけか。「さて、それじゃあ、乾杯しよう。フィットア領のブエナ村の二人の再開に」「……そして、俺とシルフィの未来に」「か、乾杯!」 あうぅ。 未来って。
SENT_117 0.264938235283  ボクはアリエル様との作戦で考えた、キメ台詞を言った。「じゃ、じゃあ、どうぞ。お召し上がりください」 それを言った瞬間。 ボクはベッドの上に放り投げられるように、押し倒された。 そして……。---ルーデウス視点--- 目が覚めた。 二段ベッドの天井が見える。
SENT_106 0.263077437878 「それは?」「えっと、その、ルディのあれに効くっていう薬なんだ」 ルディに媚薬をどうやって飲ませるか、という点ではボクも悩んだ。 こっそりとお酒に混ぜてもよかったけど、ルディを騙すのは気が引けた。 かといって、媚薬を用意した、なんて言って、変な誤解をされるのもちょっと嫌だった。 なので、薬という言い方をする。 媚薬だって薬だし、間違ってはいない。「そうなんですか……どっかで見たことありますね」「う、うん。飲んでみて欲しいんだ」 ボクがそう言うと、ルディは寂しげに笑った。
SENT_92 0.258229285479 「じゃあ、行ってきます」 シルフィは戦士の顔で、生徒会室を後にした。 目指すは街の商業区。 酒屋である。「では、私たちも行きましょうか」「はい」 シルフィを見届けて、二人も生徒会室を後にした。 昼休みはとっくに終わっていたのである。---シルフィ視点
ERROR: SENT_8771 0.240650624037  俺はすぐさま、魔王を説得するために口を開いた。「これまでの経緯から、リューンハイトの太守アイリアは合理的な思考の持ち主で、聡明で誠実と判断しております」 もちろん本心だ。彼女は間違いなく、太守の器だと思う。「また我が軍はリューンハイトの諸勢力との関係も良好であり、この同盟によって致命的な問題が発生する可能性は低いと思われます」 一番面倒くさい衛兵隊と輝陽教がおとなしくなったので、大きな障害は何もない。 魔王は俺の意見を黙って聞いていたが、やがて深くうなずいた。「我が軍に大きな利のある提案だ。しかし事は魔王軍の未来に関わることゆえ、慎重に検討せねばならぬ」 やはり少し時間が必要か……。 魔王は手元の書類をめくりながら尋ねた。「ときにトゥバーン攻略の際に、『竜の息吹』を全て使ったと聞いておる。相違ないか?」
SENT_1527 0.234314829111  そうしよう。--- それから二週間後。 その町は他に類を見ない不思議な檻に閉じ込められている。 広大な砂漠の中に、白く巨大な檻があるのだ。 何かと思ってその檻に近づいてみると、なんとそれは骨なのだ。 巨大なベヒーモスの骨なのだ。 ラパンとは町ひとつ覆うほどの巨大な肋骨の中に作られた町なのだ。 かつて小さなオアシスでしかなかったここは、ベヒーモスの死骸によって変貌した。 驚くほど多くの迷宮が出現し、数多くの冒険者を魅了する土地となったのだ。
SENT_99 0.225073978305 「あ、そうなんだ。へぇ、すごいね」 ルディの自作か、なら納得だ。 そう思いつつ、ボクはお酒の封を破って、中身を注いだ。 琥珀色の綺麗な液体が、コップを満たした。 ルディはそれを見て、目を細めた。「随分強そうな酒だな」「うん。お酒のことはよくわからないけど、高いのを買ってきたんだ」「大丈夫なのか?」「ん? うん、大丈夫だよ。今日はお祝いだからね」 値段の事を気にしているんだろうか。
SENT_2718 0.224985778332 「はい」 エリナリーゼはゆっくりと身をかがめ、クリフの額に口付けをする。 唇ではなく、額だ。 この儀式は、聖ミリスの逸話をなぞらえているらしい。 かつて聖ミリスが死地へと赴く時『最も愛すべき者』に首飾りを譲渡した。 『最も愛すべき者』は聖ミリスの額に、帰還の願いのこもった口付けを返した。 聖ミリスが窮地に陥った時、『最も愛すべき者』は神に首飾りを捧げた。 首飾りの精緻さと『最も愛すべき者』の愛に感心した神は、聖ミリスを助けたという。 そんな逸話だ。 この世界の話はフィクションなのかそうでないのか、判別しにくい。
SENT_102 0.216475516558  そうなのか、知らなかった。 ルディはやれやれって感じで、苦笑していた。「しょうが無いじゃないか、今までお酒なんて飲んだ事ないんだもん」「いや、咎めるわけじゃないんだけどな、ちょっとまってろ」 ルディはそう言いつつ、ボクのコップの中身を自分のコップに移して、 ボクのコップにお湯を注いだ。 無詠唱魔術でだ。 ボクのコップからは、ホカホカと湯気の立つようになった。「どうぞ」 勧められて、恐る恐る飲んでみる。
SENT_478 0.214859455824  そういう図式である。 これでは意味が無い。 けど、ただ教えてもらうのでは、彼女の気が済まないらしい。 シルフィは尽くすタイプなのだろうか。 自分から何かしていないと気が済まないタイプなのだろうか。 相手から何かをされると心苦しく思うタイプなのだろうか。 しかし、無詠唱の治癒魔術は今まで出来なかったことである。 ありがたく教えてもらうことにした。 まあ、また何かシルフィの様子を見て提案していけばいいだろう。 さて。
SENT_2277 0.214440017939  俺は生涯、シルフィを愛そう。 不安もあったろうに、わめきたいだろうに、俺のやることを文句もなく受け入れてくれたシルフィを。「シルフィ」「えへへ」 俺もおかえしに、シルフィにキスをする。 ぷにぷにと柔らかいシルフィの柔らかな頬に。「……」 いつもだったら、ここから本番へと突入する所だ。 だが、今日はここまでだ。 身重のシルフィに無理をさせるわけには行かないからな。	

実験2. 「人狼への転生」のある段落に対して近い類似度を持つtop 10件を計算する

9/10件が仮定通り、同じ著者の文章の塊となりました。

INPUT  太刀筋はまあまあだ。逃げずに向かってきたし、一応プロといってもいい。 だが日頃ろくすっぽ鍛えていないのか、足運びが良くなかった。人狼の眼には立ち止まっているようにしか見えない。 強化術で加速した俺は、剣客たちを軽いボディブローで順番に沈める。ついでなので作務衣の男たちも同様に沈めていく。もはやただの単純作業だ。 鎧を着ていない人間が相手だと、ダメージの予想がしやすいから手加減も楽だな。 そのとき、小屋の中で悲鳴が聞こえた。「ぎゃっ!?」「ごめーん、隊長。やっちゃった」 のんびりとしたモンザの声が聞こえてくる。 俺は駆けつけてきたジェリク隊に犯罪者どもの捕縛を任せて、小屋の中に入る。 薄暗い小屋の中に人狼形態のモンザが立っていて、首を失った剣客の死体が転がっていた。
SENT_7642 0.250458329916  変な遠吠えも聞こえてくる。聞き覚えのない声も混ざっていた。 人間がいなくて、みんなが敵を探していて、知らない遠吠えがある。 考えられる可能性は、ひとつしかない。 俺は人狼に変身し、全員に叫んだ。『集マレ!』 即座にいくつもの遠吠えが呼応し、俺の周囲に人狼の気配が満ちてくる。「おい大将、人間がどこにもいないぜ!?」 魔撃銃を担いだジェリクが、分隊員を連れて駆けつけてきた。 他の分隊も次々に集まってくる。 俺は首を横に振り、彼らに警戒を命じた。
SENT_6611 0.23514854908  人狼隊の負傷者は三名。まともに矢を受けてしまった者たちだ。「三人とも、勇敢に戦ってくれたな。大丈夫だ、すぐ治る」 俺は負傷兵に治療魔法をかけてやりながら、彼らの健闘を称えた。 他にもかすり傷を受けていた者は数名いたが、みんな元気そうだ。さすがに人狼だけのことはある。 俺は後のことをジェリクに任せると、急いで城門に戻った。気になることがあったのだ。「あ、隊長」 モンザが困ったような顔をして、俺を出迎えてくれた。どうやら俺の予想通りだったか。「こいつらを見て。ナイフ持って近くをうろうろしてたの」 彼女の足下には、数名の男たちが座らされている。周辺には銀細工のナイフが転がっていた。 男たちの顔がボコボコに歪んでいたので、俺はおそるおそるモンザに尋ねる。
SENT_8298 0.231359869242  俺はジェリクたちに告げる。「俺たちは今、油まみれで焚き火にあたっているのと同じだ。今この瞬間に魔力が暴走して、この森が吹き飛んでもおかしくない」「大将がそこまで言うんなら、ずらかったほうがよさそうだな」 ジェリクはまじめな顔をしてうなずく。 だが彼はすぐに、こうも言った。「でも大将のことだから、また無茶するんだろ? つきあうぜ」「いや、無茶は滅多にしてないが……」 あの装置の停止か回収は急務だ。俺は魔法装置は専門じゃないからわからないが、あれが暴走したら森が吹き飛ぶ程度で済まない可能性もある。 俺はジェリク隊からジェリクとゲオルを残し、あとの二人を多聞院とアイリアへの急使として派遣することにする。 すると祠から出てきたイズシが、握り飯をもしゃもしゃ食いながらのんびりと声をかけてきた。
ERROR: SENT_4653 0.225318059325 「で、新入り、名前は?」「ギースだ」「大佐か?」「たいさ? いや、冒険者だ、一応な」 ギース。 はて、どこかで聞いた事があるような気がする。 どこだったか。 思い出せない。 まあ、似たような名前は多そうだが。「俺はルーデウスだ。
SENT_8335 0.2250392735 「ウォーロイ、貴殿に来てくれと頼んだ覚えはないぞ?」「まあそう言うな、決闘卿ヴァイト。他国の様子は自分の目で見ておきたい」 当たり前のような顔をして威風堂々と突っ立っているのは、ロルムンドを追われた流浪の皇子ウォーロイだ。 ウォーロイは道中で買い込んだらしい十文字槍を担いで、着流し姿で辺りを見回している。なかなか似合っているが、意外とミーハーだな、こいつ。「キマイラ退治と聞いて駆けつけたのだが、相手はどこだ?」「もう倒した」「はっはっは、相変わらず手が早いな!」 バンバン背中を叩かれる俺。 そして左右からはリュッコとカイト。 なんだか急に身動きしにくくなった気がする。
SENT_7805 0.223653554916  そのままクリーチ湖上城に入ったエレオラ軍は休む暇もなく、装備と編成を整えて翌日に出発する。「俺の影武者、よろしく頼む」「任せてください」 俺は行軍中に着ていた鎧とコートを人狼の一人に預け、彼を影武者にする。 俺は人狼隊と共に、ここで帝都に引き返すタイミングを狙う。「ヴァイト殿、帝都のことは任せた」「ああ、そっちも敵の総数が不明だ。死ぬなよ、エレオラ殿」 俺とエレオラは視線を交わし、別れを告げる。北ロルムンドの情勢もかなり不穏なので、正直心配ではある。 そんな俺の心配を知ってか知らずか、エレオラは兵たちに号令を下す。「これより我が軍は北ロルムンドの領土防衛に向かう! ただの反乱鎮圧と侮るな! 行くぞ!」
SENT_7276 0.221946910024 「なるほど、やっぱり隊長は悪党だな」「ああ、人間の弱い心をよく知り尽くしている」 その言葉に、俺は思わず苦笑する。「人間の弱い心については、俺もかなり学んだからな……」 前世も今世も、俺は弱い心の持ち主だ。 ハマーム隊のみんなは俺の言葉を聞いて誤解したらしく、「さすがは大賢者の弟子だ」と感心している。 ますます照れくさくなった俺は、一同に命じた。「この調子で脱走兵から情報を集めるんだ。ひとつひとつは不正確でも、集まれば信頼性が増す。頼んだぞ」「はっ!」 ウォーロイ軍の士気は下がっているようだったが、俺たち雪の砦の兵士たちは妙に絶好調だった。
SENT_8222 0.221321418881  ふふん、貴殿の忍術のタネはわかったぞ。 俺も微笑みで返してやる。 ただわからなかったのは、どうやったらそんなに都合良く糸を配置できるかなのだが……。 するとフミノは俺の表情を見て理解したのか、一瞬だけ勝ち誇った顔をする。「我ら観星衆は占星術師を祖に持つ一門。予知の術に長けておりますれば」 なるほど。 相手の未来位置を予測して、そこに仕掛けておいたらしい。 予知魔法の使い手が武器で戦うときによく使う方法だ。 でも俺に教えて良かったのだろうか。 そのことはフミノもハッと気づいたらしく、声を低くしてゲヘエに詰め寄る。
SENT_7297 0.218523964286  放たれた光弾の数を見た限りでは、守備隊における魔撃兵の比率は高い。そのぶん他の兵は少ないはずだ。「だが追撃してきた敵は、一発の光弾も放つことはなかった。つまり魔撃兵は全て砦に温存されている。これ以上の追撃はないだろう」 予想通り慎重に仕掛けてきたな。さすがはヴァイトというところか。 あの男、派手な言動とは裏腹に用心深い。 まるで狼だ。 すると別の騎士が訴えかける。「しかし殿下は全軍の大将です。どうかお急ぎください。我らは後方を守りながらお供します」「いや、お前たちがいないと素裸で戦場をうろついている気分でな。鎧だけ置いて先には進めん。共に行こう」「殿下……」 いちいちしんみりするな。戦場だぞ。
SENT_7215 0.217322960496 「いずれにせよ、よくこの街を守った。その後の処理も上出来といえよう」「あ、ありがとうございます」「じゃから安心して、魔王様に申し開きしてくるがよい」 文字通り降って湧いた大量の積雪で、「炎上王女と雪の城」は無事に完成した。 分厚い雪の壁……石の壁よりずっと脆く軽いので、厚くせざるを得なかったのだが、とにかく分厚い壁だ。 高さも十分にあり、攻城兵器がなければ攻略は不可能だろう。「これ投石機の攻撃くらっても、翌日には直りますよね」 カイトがそびえ立つ白銀の壁を見上げながら、あきれたようにつぶやく。「飛んできた石、壁の中に埋めちゃえばいいんですから」「まあ……そうだな

レコメンデーションシステムへの応用

  Doc2Vecが、潜在的になんらかの文章の特徴を用いて近しい文章を検索できるようであるとことは確かそうでした。ただ、人間からみて、文章の作りが構造的に近いなどはさほど重要でなく、あまり意味のない特徴量でコンテンツを引いてしまうのではないかなという心配があります。
 先行研究ではツイッターのようなマイクロブログまで意識するとLDAのほうが望ましいらしいということがわかっています。LDAとDoc2Vecの両方の仕組みで一度レコメンドシステムを実装してユーザビリティが高い方を採用したいと考えています。