人生において何度も同じようなのを書いていますが、あらためて Perl によるコサイン類似度の計算。他で使っているコサイン類似度計算のコードの動作確認用。
コマンドラインオプション:
- "-c" : 出現頻度をそのまま使う。指定なしだと頻度は全て1。
- "-t" : TF-IDF での頻度補正を行う。
出力:
- 入力された各行ごとに計算した類似度。
- 先頭の二つの数字が入力行番号(1始まり)。
■コード (cossim.pl)
■実行例
http://www.cse.kyoto-su.ac.jp/~g0846020/keywords/cosinSimilarity.html
[2] IIR C6
http://nlp.stanford.edu/IR-book/pdf/06vect.pdf
[3] perlでコサイン類似度を算出 (end0tknrのkipple - web写経開発)
http://d.hatena.ne.jp/end0tknr/20111021/1319162866
[4] Perlでコサイン類似度を計算する (work.log)
http://worklog.be/archives/3206
[5] コサイン尺度(コサイン類似度)の計算 (Ceekz Logs)
http://private.ceek.jp/archives/003891.html
コマンドラインオプション:
- "-c" : 出現頻度をそのまま使う。指定なしだと頻度は全て1。
- "-t" : TF-IDF での頻度補正を行う。
出力:
- 入力された各行ごとに計算した類似度。
- 先頭の二つの数字が入力行番号(1始まり)。
■コード (cossim.pl)
#!/usr/bin/env perl use strict; use warnings; use List::Util qw(sum); use Getopt::Long; my $opt_count = 0; # 実際の頻度を使用 my $opt_tfidf = 0; # TF-IDF で頻度補正 GetOptions( "count" => \$opt_count, "tfidf" => \$opt_tfidf, ); ### 入力 my @ents; while (<>) { chomp; next if /^\s*$/; next if /^\#/; push @ents, [split(/\s+/, $_)]; } ### 出現頻度カウント my $N = @ents; my @tf; my %df; for (my $i = 0; $i < $N; $i++) { if ($opt_count) { $tf[$i]{$_}++ for @{$ents[$i]}; } else { $tf[$i]{$_} = 1 for @{$ents[$i]}; } $df{$_}++ for keys %{$tf[$i]}; } for (my $i = 0; $i < $N; $i++) { my @vals = values %{$tf[$i]}; if ($opt_tfidf) { my $n = sum(@vals); $tf[$i]{$_} = $tf[$i]{$_}/$n * log($N / $df{$_}) for keys %{$tf[$i]}; } my $len = sqrt(sum(map {$_**2} @vals)); # ベクトルの長さ $_ /= $len for values %{$tf[$i]}; # 長さで正規化 } ### 出力 for (my $i = 0; $i < $N; $i++) { for (my $j = $i + 1; $j < $N; $j++) { my $sim = sum(map {$tf[$i]{$_} * ($tf[$j]{$_}||0)} keys %{$tf[$i]}); printf "%d %d %.8f\n", $i+1, $j+1, $sim; } }
■実行例
% cat test-1.txt hoge huga huga foo foo foo hoge hoge hoge huga % ./cossim.pl -c test-1.txt 1 2 0.42257713 (ref. [3]) % cat test-2.txt リンゴ リンゴ バナナ リンゴ バナナ ミカン % ./cossim.pl test-2.txt 1 2 0.81649658 (ref. [4]) % cat test-3.txt 日本 今日 今日 今日 高校 高校 国語 日本 日本 明日 大学 数学 % ./cossim.pl -c test-3.txt 1 2 0.19518001 (ref. [5]) % cat cossim-test.txt 六本木 渋谷 恵比寿 目黒 目黒 六本木 渋谷 渋谷 恵比寿 六本木 六本木 渋谷 渋谷 目黒 % ./cossim.pl cossim-test.txt 1 2 0.86602540 1 3 0.86602540 2 3 0.66666667 % ./cossim.pl -c cossim-test.txt 1 2 0.61721340 1 3 0.75592895 2 3 0.81649658 % ./cossim.pl -t cossim-test.txt 1 2 0.00395490 1 3 0.00395490 2 3 0.00000000 % ./cossim.pl -c -t cossim-test.txt 1 2 0.00126839 1 3 0.00165702 2 3 0.00000000
参考
[1] コサイン類似度http://www.cse.kyoto-su.ac.jp/~g0846020/keywords/cosinSimilarity.html
[2] IIR C6
http://nlp.stanford.edu/IR-book/pdf/06vect.pdf
[3] perlでコサイン類似度を算出 (end0tknrのkipple - web写経開発)
http://d.hatena.ne.jp/end0tknr/20111021/1319162866
[4] Perlでコサイン類似度を計算する (work.log)
http://worklog.be/archives/3206
[5] コサイン尺度(コサイン類似度)の計算 (Ceekz Logs)
http://private.ceek.jp/archives/003891.html
この記事に言及しているこのブログ内の記事