AI-DecisionTree
view release on metacpan or search on metacpan
Changes
INSTALL
Instance/Instance.pm
Instance/Instance.xs
Instance/Makefile.PL
Instance/t/01-basic.t
Instance/t/02-leaktest.t
Instance/typemap
LICENSE
MANIFEST
META.yml
Makefile.PL
README
SIGNATURE
dist.ini
eg/example.pl
lib/AI/DecisionTree.pm
t/01-simple.t
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
SHA1 e01a2ac643b28c7aa7d0d07a8185899a6aa32b13 Changes
SHA1 96da61eea928700509e1a616e036564035244a72 INSTALL
SHA1 7895b6323a97d46368eed8d0386db448d7e7dea0 Instance/Instance.pm
SHA1 98866c7c1b5c1bf6fd38b762ccb6bf6b053045df Instance/Instance.xs
SHA1 998f560a410f706d948b4bc373a99a00bea4f9ac Instance/Makefile.PL
SHA1 fe6397abc886b83d6f61f8efc9fd5d41a5d73ec6 Instance/t/01-basic.t
SHA1 2398adf915f9ac9383783ff279394f78138b805d Instance/t/02-leaktest.t
SHA1 57eae1c6196bbd84c32eb08e1b9db3b2d4e394b0 Instance/typemap
SHA1 b33df3650303ca968f350ac6a976f34f41762851 LICENSE
SHA1 7d2f601dbd1f9ae98ef59cacd828f7ce2675cd9c MANIFEST
SHA1 fc7255a5efe2c3b3cbc1bbb8f099e62f51cc9d5b META.yml
SHA1 f3f560a3566adacd46cab640a59fba80a910092c Makefile.PL
SHA1 812540cf2be2d26d622a363c9ea6fb76c3983995 README
SHA1 b5b9aafd9c2d8e21e669506b46a5e1f0387d0bcc dist.ini
SHA1 73ad1b764e8b3ca6cc3a204a4260e53f14cbc6a0 eg/example.pl
SHA1 d28b3d5fbbe669456f9f1c73d198d0be1dfaa872 lib/AI/DecisionTree.pm
SHA1 cc1fbcb2131905c9474ac2d38abac368dd1a5d20 t/01-simple.t
SHA1 8dd1b0848cd98888419bdbace9453dbc978275b0 t/02-noisy.t
eg/example.pl view on Meta::CPAN
outlook => 'sunny',
temperature => 'hot',
humidity => 'normal',
wind => 'strong',
} );
print "Result 2: $result\n"; # yes
# Show the created tree structure as rules
print map "$_\n", $dtree->rule_statements;
# Will barf on inconsistent data
my $t2 = new AI::DecisionTree;
$t2->add_instance( attributes => { foo => 'bar' },
result => 1 );
$t2->add_instance( attributes => { foo => 'bar' },
result => 0 );
eval {$t2->train};
print "$@\n";
lib/AI/DecisionTree.pm view on Meta::CPAN
my ($self, %args) = @_;
my $instances = $args{instances};
print STDERR '.' if $self->{verbose};
$self->{depth} = $self->{curr_depth} if $self->{curr_depth} > $self->{depth};
local $self->{curr_depth} = $self->{curr_depth} + 1;
$self->{nodes}++;
my %results;
$results{$self->_result($_)}++ foreach @$instances;
my @results = map {$_,$results{$_}} sort {$results{$b} <=> $results{$a}} keys %results;
my %node = ( distribution => \@results, instances => scalar @$instances );
foreach (keys %results) {
$self->{prior_freqs}{$_} += $results{$_};
}
if (keys(%results) == 1) {
# All these instances have the same result - make this node a leaf
$node{result} = $self->_result($instances->[0]);
return \%node;
lib/AI/DecisionTree.pm view on Meta::CPAN
}
return \%node;
}
sub best_attr {
my ($self, $instances) = @_;
# 0 is a perfect score, entropy(#instances) is the worst possible score
my ($best_score, $best_attr) = (@$instances * $self->entropy( map $_->result_int, @$instances ), undef);
my $all_attr = $self->{attributes};
foreach my $attr (keys %$all_attr) {
# %tallies is correlation between each attr value and result
# %total is number of instances with each attr value
my (%totals, %tallies);
my $num_undef = AI::DecisionTree::Instance::->tally($instances, \%tallies, \%totals, $all_attr->{$attr});
next unless keys %totals; # Make sure at least one instance defines this attribute
my $score = 0;
lib/AI/DecisionTree.pm view on Meta::CPAN
my $self = shift;
my ($tree) = @_ ? @_ : $self->{tree};
# build tree:
# [ question, { results => [ question, { ... } ] } ]
return $tree->{result} if exists $tree->{result};
return [
$tree->{split_on}, {
map { $_ => $self->rule_tree($tree->{children}{$_}) } keys %{$tree->{children}},
}
];
}
sub rule_statements {
my $self = shift;
my ($stmt, $tree) = @_ ? @_ : ('', $self->{tree});
return("$stmt -> '$tree->{result}'") if exists $tree->{result};
my @out;
lib/AI/DecisionTree.pm view on Meta::CPAN
This can be helpful for scrutinizing the structure of a tree.
Note that while the order of the rules is unpredictable, the order of
criteria within each rule reflects the order in which the criteria
will be checked at decision-making time.
=item as_graphviz()
Returns a C<GraphViz> object representing the tree. Requires that the
GraphViz module is already installed, of course. The object returned
will allow you to create PNGs, GIFs, image maps, or whatever graphical
representation of your tree you might want.
A C<leaf_colors> argument can specify a fill color for each leaf node
in the tree. The keys of the hash should be the same as the strings
appearing as the C<result> parameters given to C<add_instance()>, and
the values should be any GraphViz-style color specification.
Any additional arguments given to C<as_graphviz()> will be passed on
to GraphViz's C<new()> method. See the L<GraphViz> docs for more
info.
t/01-simple.t view on Meta::CPAN
temperature => 'mild',
humidity => 'high',
wind => 'strong',
);
my $result = $dtree->get_result( callback => sub { $attributes{$_[0]} } );
ok $result, 'no';
}
#print map "$_\n", $dtree->rule_statements;
#use YAML; print Dump $dtree;
if (eval "use GraphViz; 1") {
my $graphviz = $dtree->as_graphviz;
ok $graphviz;
if (0) {
# Only works on Mac OS X
my $file = '/tmp/tree.png';
open my($fh), "> $file" or die "$file: $!";
t/01-simple.t view on Meta::CPAN
my $t1 = new AI::DecisionTree;
my $t2 = new AI::DecisionTree;
my @train = (
[farming => 'sheep very valuable farming'],
[farming => 'farming requires many kinds animals'],
[vampire => 'vampires drink blood vampires may staked'],
[vampire => 'vampires cannot see their images mirrors'],
);
foreach my $doc (@train) {
$t1->add_instance( attributes => {map {$_,1} split ' ', $doc->[1]},
result => 0+($doc->[0] eq 'farming'));
}
foreach my $doc (@train) {
$t2->add_instance( attributes => {map {$_,1} split ' ', $doc->[1]},
result => 0+($doc->[0] eq 'vampire'));
}
$t1->train;
$t2->train;
ok(1);
my @test = (
[farming => 'I would like to begin farming sheep'],
[vampire => "I see that many vampires may have eaten my beautiful daughter's blood"],
);
foreach my $doc (@test) {
my $result = $t1->get_result( attributes => {map {$_,1} split ' ', $doc->[1]} );
ok $result, 0+($doc->[0] eq 'farming');
$result = $t2->get_result( attributes => {map {$_,1} split ' ', $doc->[1]} );
ok $result, 0+($doc->[0] eq 'vampire');
}
}
{
my $t1 = new AI::DecisionTree(purge => 0);
my $t2 = new AI::DecisionTree;
$t1->add_instance( attributes => { foo => 'bar' },
result => 1, name => 1 );
t/02-noisy.t view on Meta::CPAN
chomp $names[-1];
# Train on first 600 instances
printf "Loading 600 training instances with %d attribute types each\n", scalar @names;
while (<DATA>) {
last unless 2..601;
chomp;
my @values = split /, /, $_;
my $result = pop @values;
my %pairs = map {$names[$_], $values[$_]} 0..$#names;
$dtree->add_instance(attributes => \%pairs,
result => $result,
);
}
print "Building decision tree\n";
$dtree->train;
ok(1);
# Test on rest of data, get at least 80%
print "Testing on remainder of data\n";
my ($good, $bad) = (0,0);
while (<DATA>) {
chomp;
my @values = split /, /, $_;
my $result = pop @values;
my %pairs = map {$names[$_], $values[$_]} 0..$#names;
my ($guess, $confidence) = $dtree->get_result(attributes => \%pairs);
$guess ||= ''; $confidence ||= '';
($guess eq $result ? $good : $bad)++;
#print "$guess : $result : $confidence\n";
}
my $accuracy = $good/($good + $bad);
ok $accuracy > .8;
print "Accuracy=$accuracy\n";
#use YAML; print Dump($dtree->rule_tree);
#print map "$_\n", $dtree->rule_statements;
if (eval "use GraphViz; 1") {
my $graphviz = $dtree->as_graphviz;
ok $graphviz;
if (0) {
# Only works on Mac OS X
my $file = '/tmp/tree2.png';
open my($fh), "> $file" or die "$file: $!";
print $fh $graphviz->as_png;
( run in 1.097 second using v1.01-cache-2.11-cpan-49f99fa48dc )