この記事はアクトインディ Advent Calendar 2015 1日目になります。
どうぞよろしくお願いします。
要旨
アクトインディの運営する子どもとお出かけ情報サイト いこーよでは、日々、おでかけスポットの口コミがユーザーから投稿されています。
中には、おでかけスポットへの苦情や不満が書かれた口コミがあります。
そういったものを早期に検出するためSolrの類似文書検索(MoreLikeThis)機能を使用し機械的な検出を試みました。
決して精度は高くありませんが、Sunspotを使用し極めて簡単に実装できました。
使用しているデータは実際のものとは異なります。
検出方法
やりたいことは文書分類問題なので、機械学習などいろいろな方法があります。
いこーよでは全文検索エンジンにSunspot経由でSolrを使っているため、手軽に実装できることから、今回はMoreLikeThisを試してみました。
準備
SunspotからMoreLikeThisの使い方はSunspotのドキュメントにあります。
MoreLikeThisを使用するためにはSolrのMoreLikeThisHandlerを有効にする必要があります。solrconfig.xmlにrequestHandlerを追加します。
<requestHandler class="solr.MoreLikeThisHandler" name="/mlt">
</requestHandler>
次にmodelクラスへ検索用フィールドを追加します。
class Kuchikomi < ActiveRecord::Base
searchable do
text :body, more_like_this: true
end
end
あとはsolrのindexを作り直せば検索可能になります。Sunspot便利ですね。
Kuchikomi.reindex
Sunspot.more_like_this(Kuchikomi.first) {
fields :body
minimum_term_frequency 1
minimum_document_frequency 2
}.results
=> ...
判定
類似文書が取れるようになりましたので、次はその文章が苦情かどうかの判定になります。
今回はお試しなので、今までに投稿された低評価の口コミを苦情正解セットとして扱います。
判定は次のように行います。
- 投稿された口コミから類似文書を検索
- ヒットした口コミ群がこの苦情セットに含まれるか判定
- 苦情正解セットに一定数以上含まれた場合、投稿された口コミを苦情と判定
実際に書いてみると次のようになります。
n = 5
complaints = Set.new(Kuchikomi.where(rating: 'low').pluck(:id))
k = Kuchikomi.new(body: '店員の態度が最悪でした。私気分悪帰')
k.save!
k.index!
hits = Sunspot.more_like_this(k) {
fields :body
minimum_term_frequency 1
minimum_document_frequency 2
}.hits.map{ |h| h.primary_key.to_i }
if (complaints & hits).size > n # hit数
puts '苦情です!"
end
これで苦情の検出が可能になりました。
結果
ここまで検出器を作ってきましたが、サンプルデータで動かした場合、精度はあまり良くありませんでした。
あからさまにhit数が多いものとhit数が0のものに関してはほとんどが正解でしたが、hit数が2,3件で苦情口コミと通常の口コミの判定が混在します。
hit数5件以上はほぼ苦情でした。
考察
精度を高めて、実務に使うためには
- 正解セットの選別
- minimum_term_frequency, minimum_document_frequencyなどのパラメーター
- 判定閾値
- 偽陰性、偽陽性はトレードオフなのでどちらに寄せるか
- 判定結果の定量的な評価方法
などが必要そうです。
とはいえ、実装自体はSunspotをすでに使用していれば簡単なので、とりあえずやってみようといったときには便利です。
次はRandomForestを試してみようと思います。