Algorithm-Classifier-IsolationForest

 view release on metacpan or  search on metacpan

benchmarking/bench-axis-predict-accel.pl  view on Meta::CPAN

	for ( 1 .. int( $n * 0.05 ) ) {
		my $r = 5 + rand() * 3;
		push @rows, [ map { $r * ( rand() > 0.5 ? 1 : -1 ) } 1 .. $nf ];
	}
	return \@rows;
} ## end sub make_data

my $HAS_C      = $Algorithm::Classifier::IsolationForest::HAS_C;
my $HAS_OPENMP = $Algorithm::Classifier::IsolationForest::HAS_OPENMP;

# Build one model per accel config.  They share the same seed and training
# data so tree structure is identical -- only the scoring path differs.
sub build_models {
	my (%opts) = @_;
	my $data = delete $opts{_data};
	my %m;
	$m{pure_perl} = Algorithm::Classifier::IsolationForest->new( %opts, use_c => 0, )->fit($data);
	if ($HAS_C) {
		$m{c_serial} = Algorithm::Classifier::IsolationForest->new(
			%opts,
			use_c      => 1,
			use_openmp => 0,
		)->fit($data);
	}
	if ( $HAS_C && $HAS_OPENMP ) {
		$m{c_openmp} = Algorithm::Classifier::IsolationForest->new(
			%opts,
			use_c      => 1,
			use_openmp => 1,
		)->fit($data);
	}
	return \%m;
} ## end sub build_models

print "=" x 70, "\n";
print " axis-mode scoring/predict accel benchmarks\n";
print " Algorithm::Classifier::IsolationForest\n";
print "=" x 70, "\n";
printf "Backend availability: HAS_C=%d  HAS_OPENMP=%d  HAS_SIMD=%d\n",
	$HAS_C, $HAS_OPENMP,
	$Algorithm::Classifier::IsolationForest::HAS_SIMD;
print "(rates shown as calls/second wall-clock; higher is faster)\n";

# -----------------------------------------------------------------------
# 1. Scoring method comparison  (n_trees=100, 1000 query points)
# -----------------------------------------------------------------------
print "\n--- scoring methods  (n_trees=100, 1000 query points, 2 features) ---\n";
srand(42);
my $train  = make_data( 1000, 2 );
my $q1k    = make_data( 1000, 2 );
my $models = build_models(
	n_trees     => 100,
	sample_size => 256,
	mode        => 'axis',
	seed        => 1,
	_data       => $train,
);

for my $method (
	qw(score_samples predict score_predict_samples
	score_predict_split path_lengths)
	)
{
	printf "\n  %s\n", $method;
	my %v;
	for my $accel ( sort keys %$models ) {
		my $m = $models->{$accel};
		if (   $method eq 'predict'
			|| $method eq 'score_predict_samples'
			|| $method eq 'score_predict_split' )
		{
			$v{$accel} = sub { $m->$method( $q1k, 0.5 ) };
		} else {
			$v{$accel} = sub { $m->$method($q1k) };
		}
	} ## end for my $accel ( sort keys %$models )
	wall_cmpthese( -2, \%v );
} ## end for my $method ( qw(score_samples predict score_predict_samples...))

# -----------------------------------------------------------------------
# 2. Query set size scaling  (n_trees=100, score_samples)
# -----------------------------------------------------------------------
print "\n--- query set size  (n_trees=100, score_samples, 2 features) ---\n";
srand(99);
my %q;
$q{$_} = make_data( $_, 2 ) for ( 100, 500, 1_000, 5_000, 10_000 );
for my $n ( 100, 500, 1_000, 5_000, 10_000 ) {
	printf "\n  %d query points\n", $n;
	my %v;
	for my $accel ( sort keys %$models ) {
		$v{$accel} = sub { $models->{$accel}->score_samples( $q{$n} ) };
	}
	wall_cmpthese( -2, \%v );
}

# -----------------------------------------------------------------------
# 3. n_trees scaling  (1000 query points, score_samples)
# -----------------------------------------------------------------------
print "\n--- n_trees effect  (1000 query points, 2 features) ---\n";
srand(42);
my $train2 = make_data( 1000, 2 );
for my $nt ( 10, 50, 100, 200, 500 ) {
	printf "\n  n_trees=%d\n", $nt;
	my $ms = build_models(
		n_trees     => $nt,
		sample_size => 256,
		mode        => 'axis',
		seed        => 1,
		_data       => $train2,
	);
	my %v;
	for my $accel ( sort keys %$ms ) {
		$v{$accel} = sub { $ms->{$accel}->score_samples($q1k) };
	}
	wall_cmpthese( -2, \%v );
} ## end for my $nt ( 10, 50, 100, 200, 500 )

# -----------------------------------------------------------------------
# 4. Feature count (wide range)
# -----------------------------------------------------------------------
print "\n--- feature count  (n_trees=100, 1000 query points) ---\n";



( run in 0.728 second using v1.01-cache-2.11-cpan-995e09ba956 )