2011년 7월 18일 월요일

perl로 작성한 간단한 cosine similarity 소스

 요즘에는 python이 인기가 더 많은듯 한데 개인적으로 python을 별로

 좋아하지 않는다. 사실 매우 편협한 이유인데 들여쓰기와 함수의 시작

 과 끝이 { }로 구분되지 않는다는 점때문이다.

 간단히 Cosine similarity를 구하기 위해서 python이나 perl과 같은 스크립트

 언어로 스크립트를 짜야 할 때가 많은데 다음의 cosine similarity를 구해주는

 간단한 perl 스크립트를 이용해 보시라.


 사용법은 간단하다.

 document.txt 라는 파일을 만들고 파일에 여러 다큐먼트를 다음과 같은

 포맷으로 합친후 스크립트를 그냥 실행하면 된다.

 <TITLE> doc1 </TITLE>

 This is document1.

 <TITLE> doc2 </TITLE>

 This is document2.

 소스는 별로 어렵지 않으니 다큐먼트를 합치기가 귀찮다거나 아니면

 알고리즘을 수정하고 싶다면 간단히 수정해보아도 공부하는데 도움이

 될듯하다.

 기본적으로 소스에서는 IDF를 log2 ( N / DF )로 계산하고 있다.

#!/usr/bin/perl

use strict;

open(IN, "document.txt") or die;
my $nstory = -1;
my @words;
my %granddict;
my @weight;
my @unit;
my $i;
my $j;
my @cosine;
my $word;
my $sum;
my $df;
my @tf;
my $n;
my %df;
my $len2;
my $len;

#Step 1: Compute the term frequencies

while(<IN>){
    chomp;
    my $title;
    if ( /<TITLE>(.*)<\/TITLE>/ ){
        $title = $1;
        ++$nstory;
        print "Title of story $nstory = $title \n";
    } else {
        $_ = lc;
        s/--/ /g;
        s/ - / /g;
        s/[,.";!()?:_\[\]]//g;
        s/\s+/ /g;
        s/^\s+//g;
        @words = split(/ /);
        foreach $word (@words){
            if ($word =~ /^;?(.*?)'?$/){
                $word = $1;
            }
            ++$tf[$nstory]{$word};
            ++$granddict{$word};
        }
    }
}

foreach $word (sort keys %granddict ) {
    $sum = 0;
    for $i ( 0 .. $#tf ){
        if ($tf[$i]{$word} > 0){
            ++$sum;
        }
        $df{$word} = $sum;
    }
}

$n = $#tf + 1;
foreach $word (sort keys %granddict){
    for $i (0 .. $#tf){
        $weight[$i]{$word} = $tf[$i]{$word}*log($n/$df{$word})/log(2);
    }
}

for $i ( 0 .. $#tf ) {
    $len2 = 0;
    foreach $word ( sort keys %granddict){
        $len2 += $weight[$i]{$word}**2;
    }
    $len = sqrt($len2);
    foreach $word ( sort keys %granddict){
        $unit[$i]{$word} = $weight[$i]{$word}/$len;
    }
}

for $i ( 0 .. $#tf ) {
    for $j ( 0 .. $#tf ) {
        $sum = 0;
        foreach $word ( sort keys %granddict ) {
            $sum += $unit[$i]{$word} * $unit[$j]{$word};
        }
        $cosine[$i][$j] = $sum;
    }
}

print "\n";
for $i ( 0 .. $#tf) {
    for $j (0 .. $#tf) {
        printf "%.4f ", $cosine[$i][$j];
    }
    print "\n";
}


 참고로 소스의 출처는 Practical Text Mining With Perl 이란 책이다. 

 (저작권에 걸릴려나.. ) 

 책이 text mining에 관한 기초 실무로는 딱 좋으니 관심있는 분들은

 한번 보시라.



댓글 없음:

댓글 쓰기