Algorithm-AdaBoost

 view release on metacpan or  search on metacpan

t/01_basic.t  view on Meta::CPAN

use 5.014;

use Algorithm::AdaBoost;
use Smart::Args;
use Test::More;

my @dataset = map {
  chomp;
  my ($label, $x, $y) = split /\s/;
  +{ feature => [$x, $y], label => $label };
} <DATA>;

my @training_set = @dataset[0 .. 99];
my @test_set = @dataset[100 .. 199];

my $learner = new_ok 'Algorithm::AdaBoost' => [
  training_set => \@training_set,
  weak_classifier_generator => \&generate_weak_classifier,
];
ok(
  +(not $learner->trained),
  '|trained| should be false before the learner |train|-ed.'
);

$learner->train(num_iterations => 1000);
ok($learner->trained, 'A classifier is constructed successfully.');

my $classifier = $learner->final_classifier;

my $correct = 0;
for my $test_data (@test_set) {
  my $answer = $classifier->classify($test_data->{feature}) < 0 ? -1 : 1;
  ++$correct if $answer == $test_data->{label};
}
my $accuracy = $correct / @test_set;
cmp_ok(
  $accuracy, '>', 0.65,
  'The constructed classifier should sagnificantly accurate rather than random guess'
);

done_testing;

# Generates simple linear classifier randomly.
sub generate_weak_classifier {
  args
    my $distribution => 'ArrayRef[Num]',
    my $training_set => 'ArrayRef[HashRef]';

  while (1) {
    my ($o_x, $o_y) = (rand(6) - 3, rand(6) - 3);
    my ($p_x, $p_y) = (rand(6) - 3, rand(6) - 3);
    my @normal_vector = ($p_x - $o_x, $p_y - $o_y);

    my $accuracy = 0;
    my $classifier_candidate = sub {
      args_pos my $point => 'ArrayRef[Num]';
      my ($x, $y) = @$point;
      my @position_vector = ($x - $o_x, $y - $o_y);
      my $inner_product = $normal_vector[0] * $position_vector[0]
        + $normal_vector[1] * $position_vector[1];
      return $inner_product < 0 ? -1 : 1;
    };

    for my $i (0 .. $#$distribution) {
      my $answer = $classifier_candidate->($training_set->[$i]{feature});
      $accuracy += $distribution->[$i] if $answer == $training_set->[$i]{label};
    }
    return $classifier_candidate if $accuracy > 1/2;
  }
}

# f(x, y) = 1 if x^2 + y^2 < 4, -1 otherwise.
# subject to -3 <= x < 3, -3 <= y < 3.
__DATA__
1 -0.248490100750111 -0.739693407357834
1 -0.566115592376427 -1.68714313853555
1 -0.399623250750217 1.33407775536753
-1 1.39932333014989 2.54595589010434
-1 -2.09890668052825 -2.26928674627152
-1 -1.35789686105749 -2.76051974907672
1 0.0495294874471526 -0.961790183534873
-1 -2.14562371189552 2.51764233416243
1 1.27731540363029 0.241831210669432
1 1.16150264946072 1.49304025338465
-1 -2.69274234964235 -1.46871200361485



( run in 1.080 second using v1.01-cache-2.11-cpan-71847e10f99 )