ベイジアンフィルタに手を出してみた

perlで。

CPANに「Bayes」でお伺いを立ててみると、

Algorithm::NaiveBayes

なんて言うのがヒットした。説明を見ると、ベイジアンフィルタのいくつかの実装がされているらしい。
そんなんで、適当に書いてみる。

あらかじめ、Cのソースコードperlスクリプトを、GoogleのCodeSearchあたりで拾い集め、 cは1.c..5.c、perlは1.pl..5.plというファイル名で保存しておいた。

判定に使うものはtest.txt。

use Algorithm::NaiveBayes;
use YAML;
my $nb = Algorithm::NaiveBayes->new;

# Cのソースコードを読み込み
for(1..5) {
	$nb->add_instance(
		attributes => get_hash($_.".c"),
		label => 'c'
	);
}

# perlスクリプトを読み込み
for(1..5) {
	$nb->add_instance(
		attributes => get_hash($_.".pl"),
		label => 'perl'
	);
}

# 計算!
$nb->train;

# どっち!?
my $result = $nb->predict(
	attributes => get_hash("test.txt")
);

print YAML::Dump $result;

sub get_hash
{
	my $file = shift;
	my $hash = {};
	open(INFILE, "<", $file) or die "Cannot open file: $file";
	while (<INFILE>) {
		chomp();
		
		++$hash->{$_} if($_ ne '');
	}
	return $hash;
}

普通は、単語単位でやるんだろうけど、行単位でやってみた。

判定には以下のソースコードをかませてみた。

#include <stdio.h>

int main()
{
	printf("Hello World");
	return 0;
}

結果。

---
c: 0.99943269700008
perl: 0.0336791354869307


確かにcとして判定されちょる。

試しに、get_hashを以下のように単語単位に区切るようにしてみたら、
さらに精度があがった。当然か。

sub get_hash
{
	my $file = shift;
	my $hash = {};
	open(INFILE, "<", $file) or die "Cannot open file: $file";
	while (<INFILE>) {
		chomp();
		
		for( split(/ /) ) {
			++$hash->{$_} if($_ ne '');
		}
	}
	return $hash;
}

結果

---
c: 0.999998691261783
perl: 0.00161786115610611


今度はperlを判定。
短いかなぁ? とは思ったけど、以下のを食わせてみた。

use strict;
print "Hello World";

結果

    • -
c: 0.00751176739777214 perl: 0.999971786277274

正しく判定されるもんだねぇ。