コサイン類似度を計算して二つの文章がどれ位似ているのかを判定するメモです。
Perl でこのようなコードを書くとコサイン類似度を計算できます。文章と言いながら今回は名詞レベルで比較しています。
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils;
## 各文章より抜き出した名詞
my @w1 = qw/リンゴ リンゴ バナナ/;
my @w2 = qw/リンゴ バナナ ミカン/;
my @vector = ();
my $hash = {};
## @w1, @w2 の内容を @vector に連結
push(@vector, @w1);
push(@vector, @w2);
## @w1, @w2 の内容から重複値を削除
@vector = List::MoreUtils::uniq @vector;
foreach my $vector (@vector) {
my $tmp = {};
## ベクトルに含まれる名詞がそれぞれの配列にあるかをチェック
$tmp->{w1} = grep(/^$vector$/, @w1);
$tmp->{w2} = grep(/^$vector$/, @w2);
## 名詞の数を記録 (重複カウントなし)
if ($tmp->{w1}) {
$hash->{w1_num}++;
}
if ($tmp->{w2}) {
$hash->{w2_num}++;
}
## 両方に見つかった回数を記録
if ($tmp->{w1} && $tmp->{w2}) {
$hash->{and}++;
}
}
if (!$hash->{and} | !$hash->{w1_num} || !$hash->{w2_num}) {
print "cos: 0\n";
} else {
## コサイン類似度の計算
$hash->{cos} = $hash->{and} / ( sqrt($hash->{w1_num}) * sqrt($hash->{w2_num}) );
print "cos: $hash->{cos}\n";
}
exit;
これを実行するとこうなります。
cos: 0.816496580927726
1 に近づくほど類似している事となります。
非常に参考になりました!
一つお聞きしたいのですが、配列の変数を標準入力のファイル指定に変更することはできるでしょうか?
m 様
コメントありがとうございます。
> 配列の変数を標準入力のファイル指定に変更
それぞれに指定したファイルからデータ読み込んで @w1, @w2 の値として使いたい意味でしたでしょうか ?
ファイルハンドルを使ってデータを読み込んで渡せばできると思いますが意味が違ってたらごめんなさい^^;