JavaScriptで類似度を計算する方法を書きました。
これを使って複数の文から類似度の高い文を検索する方法を考えます。
簡易形態素解析
一般的に類似度を計算する際は、まず形態素解析するのですが、とにかく簡単にやりたかったので、簡易的に形態素解析する方法を考えました。
考え方は次のとおりです。
- 検索したい単語で分割する。
- カタカタで分割する。
- 漢字で分割する。
例えば「夏目漱石の猫はパンが好き」という文があるとします。
そして「夏目」で検索するとします。
このとき、元の文は「夏目 漱石 の 猫 は パン が 好 き」となります。
function bunkatsu(text, words) {
// テキストを単語に分割する。
saki = text
for (i in words) {
word = words[i];
re = new RegExp("(" + word + ")", "g");
saki = saki.replace(re, "\t$1\t", "g")
}
// カタカナで分割
re = new RegExp("([\u30A1-\u30FF]+)", "g");
saki = saki.replace(re, "\t$1\t");
// 漢字で分割
re = new RegExp("([\u2E80-\u2FDF\u3005-\u3007\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\U00020000-\U0002EBEF]+)", "g");
saki = saki.replace(re, "\t$1\t");
results = saki.split("\t")
temps = [];
for (i in results) {
temp = results[i];
if (temp !== "") {
temps.push(temp);
}
}
return temps;
}
// テキストを単語に分割する。
saki = text
for (i in words) {
word = words[i];
re = new RegExp("(" + word + ")", "g");
saki = saki.replace(re, "\t$1\t", "g")
}
// カタカナで分割
re = new RegExp("([\u30A1-\u30FF]+)", "g");
saki = saki.replace(re, "\t$1\t");
// 漢字で分割
re = new RegExp("([\u2E80-\u2FDF\u3005-\u3007\u3400-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\U00020000-\U0002EBEF]+)", "g");
saki = saki.replace(re, "\t$1\t");
results = saki.split("\t")
temps = [];
for (i in results) {
temp = results[i];
if (temp !== "") {
temps.push(temp);
}
}
return temps;
}
テスト
target_terms = ["夏目","パン"];
sentences = [
"夏目漱石の猫はパンが好き。",
"猫がパンを食べる。",
"夏目三久は日本テレビのアナウンサー。"
]
texts = [];
for(i in sentences){
texts.push(bunkatsu(sentences[i],target_terms));
}
results = get_similar_tfidf(target_terms, texts);
console.log(results);
sentences = [
"夏目漱石の猫はパンが好き。",
"猫がパンを食べる。",
"夏目三久は日本テレビのアナウンサー。"
]
texts = [];
for(i in sentences){
texts.push(bunkatsu(sentences[i],target_terms));
}
results = get_similar_tfidf(target_terms, texts);
console.log(results);
結果
0.40, [‘夏目’, ‘漱石’, ‘の’, ‘猫’, ‘は’, ‘パン’, ‘が’, ‘好’, ‘き。’]
0.23, [‘猫’, ‘が’, ‘パン’, ‘を’, ‘食’, ‘べる。’]
0.19, [‘夏目’, ‘三久’, ‘は’, ‘日本’, ‘テレビ’, ‘の’, ‘アナウンサー’, ‘。’]
夏目とパンの両方を含む文がトップに来ました。
この仕組みを使ってチャットボットを作ってみましたが、思ったほどの精度が出ず、実際は別の手法を使いました。
コメント