まず、2個のベクトル:a,b の関係:θは、次のように表せます。
ここで、 はaとbの内積なので、2次元のベクトルであれば、 で表せ、また、 はベクトルの大きさなので、 となります。
※ベクトルの内積や大きさは、更に多次元(n次元)になると、 や
これをperlで実装すると、次のように通り。
#!/usr/local/bin/perl use strict; use Data::Dumper; my @VEC_KEYS = qw/hoge fuga foo/; #ベクトルが持つkey main(); sub main { my $vec_1 = {hoge => 1, fuga => 2, foo => 3}; my $vec_2 = {hoge => 3, fuga => 1}; my $cos_similar = cosine_similarity($vec_1,$vec_2); print "COSINE SIMILARITY : $cos_similar\n"; } sub cosine_similarity { my ($vec_1, $vec_2) = @_; return inner_product($vec_1, $vec_2) / (vector_size($vec_1) * vector_size($vec_2)); } sub inner_product { #内積 my ($vec_1,$vec_2) = @_; my $ret = 0; for my $key ( @VEC_KEYS ) { next if (not $vec_1->{$key} or not $vec_2->{$key} ); $ret += $vec_1->{$key} * $vec_2->{$key}; } return $ret; } sub vector_size { #ベクトルのサイズ my ($vec) = @_; my $sum = 0; for my $key ( @VEC_KEYS ) { $sum += $vec->{$key} * $vec->{$key}; } return sqrt($sum); }
実行結果(1に近い程、類似)
[endo@colinux tmp]$ ./foo.pl COSINE SIMILARITY : 0.422577127364258
実際に類似アイテムを探す場合は、昨日のエントリにあるMath::Combinatoricsで組み合わせを算出してから用いるとよさそう。
http://d.hatena.ne.jp/end0tknr/20111020/1319119274