work.log

元エンジニアの備忘録的ブログ

Perlでコサイン類似度を計算する

投稿:2015-01-15 16:49  更新:

Perl でコサイン類似度を計算して二つの文章がどれ位似ているのかを判定するメモです。

コサイン類似度」でググると計算式が出てきますが、これを見てもさっぱり意味がわからないので見つけた PHP プログラムを参考に Perl に書き直して見ました。

※ 参考サイトはすでに無くなっていたのでリンクを削除しました。

これが 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

参考にした PHP プログラムだと「0.81649658092773」と出るがこの微妙な差は言語の違いからだろうか ?

他の参考ページを見ると、名詞の登場回数も記録して計算しているのも見つかった。

ただ今回は、元から「重複が全くない名詞」だけで二つの類似度を比べたかったのでこの方が都合が良いんじゃないかと勝手に解釈。

というより数学がわからなさすぎて泣いた。物を作る前にもう一度勉強が必要かもしれない・・・

関連記事

コメント

  1. m より:

    非常に参考になりました!
    一つお聞きしたいのですが、配列の変数を標準入力のファイル指定に変更することはできるでしょうか?

    • miura より:

      m 様

      コメントありがとうございます。

      > 配列の変数を標準入力のファイル指定に変更

      それぞれに指定したファイルからデータ読み込んで @w1, @w2 の値として使いたい意味でしたでしょうか ?

      ファイルハンドルを使ってデータを読み込んで渡せばできると思いますが意味が違ってたらごめんなさい^^;

コメントを残す

おすすめのVPSサーバ

  • OSが選べる
  • VPS同士でLANが組める
  • 複数台構成向き

このブログで使っています。

  • 転送量が多いサービスに
  • 借りてるのは3年間一度もdown無し!

よく見られている記事

  • 本日
  • 週間
  • 月間