Algorithm-Classifier-IsolationForest

 view release on metacpan or  search on metacpan

examples/contamination-threshold.pl  view on Meta::CPAN

#     perl -Ilib examples/contamination-threshold.pl

use strict;
use warnings;
use Algorithm::Classifier::IsolationForest;
use List::Util qw(sum);

use constant PI => 3.14159265358979;
srand(11);

sub gaussian {
	my ( $mu, $sigma ) = @_;
	my $u1 = rand() || 1e-12;
	return $mu + $sigma * sqrt( -2 * log($u1) ) * cos( 2 * PI * rand() );
}

# 480 normal points + 20 outliers => the true anomaly rate is 20/500 = 4%.
my @data;
push @data, [ gaussian( 0, 1 ), gaussian( 0, 1 ) ] for 1 .. 480;
for ( 1 .. 20 ) {
	my $a = rand() * 2 * PI;
	my $r = 6 + rand() * 2;
	push @data, [ $r * cos($a), $r * sin($a) ];
}

# Tell the forest we expect ~4% anomalies.
my $iforest = Algorithm::Classifier::IsolationForest->new(
	n_trees       => 100,
	sample_size   => 256,
	contamination => 0.04,
	seed          => 42,
);

# Before fitting there is no threshold yet.
printf "decision_threshold before fit(): %s\n",
	defined $iforest->decision_threshold ? $iforest->decision_threshold : 'undef';

$iforest->fit( \@data );

printf "decision_threshold learned by fit(): %.4f\n\n", $iforest->decision_threshold;

# predict() with no arguments uses the learned threshold.
my $auto   = $iforest->predict( \@data );
my $n_auto = sum(@$auto);

# Compare with the naive fixed 0.5 cutoff on the very same model.
my $fixed   = $iforest->predict( \@data, 0.5 );
my $n_fixed = sum(@$fixed);

printf "Flagged with the learned threshold : %d / %d points (%.1f%%)\n", $n_auto,  scalar @data, 100 * $n_auto / @data;
printf "Flagged with a fixed 0.5 threshold : %d / %d points (%.1f%%)\n", $n_fixed, scalar @data, 100 * $n_fixed / @data;
printf "\n(true anomaly rate baked into the data: %.1f%%)\n",            100 * 20 / @data;

print <<'NOTE';

Takeaways:
  * decision_threshold() exposes whatever fit() learned (undef if you never set
    contamination).
  * predict() with no threshold uses that learned cutoff; pass an explicit
    threshold to override it for a single call.
  * Set contamination to your best guess of the anomaly fraction -- it doesn't
    have to be exact, it just calibrates where the cutoff lands.
NOTE



( run in 0.725 second using v1.01-cache-2.11-cpan-9581c071862 )