プログラマでありたい

おっさんになっても、プログラマでありつづけたい

Algorithm::NaiveBayes ベイズ理論を使ってコメントスパムフィルター その2

 前回試してみて、とりあえずAlgorithm::NaiveBayesでいけそうと言うことが解りました。もう少しだけ、使いやすい形にプログラムを修正。具体的には、以下の3点です。
・トレーニングした成果をファイルに残す
・2回目以降のトレーニングは、前回分の結果に差分の学習結果を追加する
・引数によって、挙動を変える。

#!/usr/bin/perl -w

use strict;
use Algorithm::NaiveBayes;
use Algorithm::NaiveBayes::Model::Frequency;
use Storable;
use Getopt::Std;
#use Digest::MD5 qw(md5_hex);
use Data::Dumper;

getopt('cfl'); #Command, File, Label
use vars qw / $opt_c $opt_f $opt_l /;

my $bayes;
my $DB    = 'bayes.db';
my $command = $opt_c;
my $file  = $opt_f;
my $label = $opt_l;

if (!defined($file)) { 
  die "usage: need -f filename?n";
}
$bayes = &loadInstance;
if ($command eq 'predict') {
  &calcPredict($file);
} elsif ($command eq 'train') {
  if (!defined($label)) {die "need -l labelname?n"};
  &trainInstance($file,$label);
}


sub calcPredict {
  my $file = $_[0];
  my %list = &getHash($file);
  my $result = $bayes->predict(
    attributes => {%list}
  );
  print Dumper($result);
}
  
sub trainInstance {
  my $file  = $_[0];
  my $label = $_[1];
  my %list = &getHash($file);
  $bayes->add_instance(
    attributes => {%list},
    label => $label,
  );
  $bayes->train;
  Storable::store($bayes => $DB );
}

sub loadInstance {
  eval {$bayes = Storable::retrieve($DB)} if -e $DB;
  $bayes ||= Algorithm::NaiveBayes->new(purge => 0);
  return $bayes;
}

sub getHash {
  my $file = $_[0];
  my %hash;
  open INFILE, "< $file" or die "Cannot open file: $file";
  while (<INFILE>) {
    chomp();
#    $_ = md5_hex($_);
    if (!$hash{$_}) {$hash{$_} = 0}; 
    $hash{$_} = $hash{$_}+1;
  }
  return %hash;
}
  eval {$bayes = Storable::retrieve($DB)} if -e $DB;
  $bayes ||= Algorithm::NaiveBayes->new(purge => 0);

オブジェクトの生成の部分で、purge=0で生成すると、$bayes->predictの部分で、

Can't locate object method "predict" via package "Algorithm::NaiveBayes::Model::Frequency"

と出てくる。マニュアルを見てみると、どうもpurge=0でも再びインスタンスを追加してtrain()しろと書いているみたいです。ソース見て、単にオブジェクトをロード出来ていないようなので、足りないと言われているAlgorithm::NaiveBayes::Model::Frequencyを呼び出してみました。すると、あっさり通りました。

 出来上がったものは、

./bayes_test.pl -c train -f spam.txt -l spam
スパムの学習

./bayes_test.pl -c train -f spam.txt -l spam
ハムの学習

./bayes_test.pl -c predict -f target.txt
スパム/ハムの判定

我ながら、使いにくいものを作ってしまったものです。