スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

MongoDBでMapReduceを使って、日本語のTF-IDFとコサイン類似度を求める (メモ)



以下のような tweets コレクションを用意する。
ここで、"tf" は Term Frequency。(名詞, 出現回数/名詞の全体数) になるように。

> db.tweets.find();
{
"_id" : ObjectId("52ad618f50433450590d0000"),
"content" : "到着後はお早めにお召し上がり下さい。",
"tf" : { "到着" : 0.33, "後" : 0.33, "早め" : 0.33 }
}


後は以下のスクリプトをぶっこむ。

// IDF Dictionary
var m = function () {
for (key in this.tf) {
emit(key, 1);
};
};
var r = function(key,values) {
return Array.sum(values);
};
var f = function(key, value) {
return Math.log(N/value);
}
db.tweets.mapReduce(m, r, {finalize: f, scope: {N: db.tweets.count()}, out: 'tweets_idf'});
db.tweet_idf.find();


// TF-IDF
db.tweets.find({},{tf:1}).forEach(function (tweet) {
var tfidf = {};
var V = 0;
for(var key in tweet.tf) {
var word = db.tweets_idf.findOne({_id : key});
var idf = 1;
if (word) {idf = word.value}
var v = tweet.tf[key] * idf;
tfidf[key] = v;
V += v * v;
}
// tfidf.v : term vector
// tfidf.l : term vector length
db.tweets.update({_id: tweet._id}, {$set: {tfidf: {v: tfidf, l: Math.sqrt(V)}}});
});


// Cosine Similarity
var m = function () {
value = 0;
for (var key in this.tfidf.v) {
v = tweet.tfidf.v[key];
if (v) {
value += this.tfidf.v[key] * v;
}
}
emit(this._id, value / this.tfidf.l / tweet.tfidf.l);
};
var r = function(key,values) {
return values[0];
};
db.tweets_similarity.drop();
var cursor = db.tweets.find({},{tfidf:1}).sort({"_id":1});
while (cursor.hasNext()) {
var tweet = cursor.next();
db.tweets.mapReduce(m, r, {scope: {tweet: tweet}, query: {_id:{$gt:tweet._id}}, out: 'tweets_tmp'});
db.tweets_tmp.find().forEach( function (dst) {
db.tweets_similarity.insert({a:dst._id, b:tweet._id, score:dst.value});
});
}


確認

db.tweets_similarity.find();


説明
・IDF(Inverse Document Frequency)の辞書を作る部分は、MapReduceのHelloWorld的な解法。
 名詞単語 -> 自然対数 ( ドキュメント総数 / その名詞が含まれるドキュメント数 )
・TF-IDFを求める部分。MapReduceでないですね。そのうち直す。
・コサイン類似度を求める部分。
 全ドキュメント同士の類似度を計算する。ドキュメント総数がN なら、N(N-1)÷2 回の類似度計算をする。

Map関数はいいが、Reduce関数の使い所が、まだよくわかってない。。。
数をカウントするくらいしか、思いつかないよ。
スポンサーサイト

コメントの投稿

非公開コメント

検索フォーム
RSSリンクの表示
リンク
exabugsをフォローしましょう
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。