Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
lib/Algorithm/Classifier/IsolationForest.pm view on Meta::CPAN
croak "sample_size must be >= 1" unless $self->{sample_size} >= 1;
croak "extension_level must be >= 0"
if defined $self->{extension_level} && $self->{extension_level} < 0;
croak "contamination must be a number in (0, 0.5]"
if defined $self->{contamination}
&& !( $self->{contamination} > 0 && $self->{contamination} <= 0.5 );
croak "parallel_fit must be a positive integer"
if defined $self->{parallel_fit}
&& ( $self->{parallel_fit} !~ /^\d+$/ || $self->{parallel_fit} < 1 );
return bless $self, $class;
} ## end sub new
=head2 decision_threshold
The score cutoff C<predict> uses by default; undef unless C<contamination> was
set.
=cut
sub decision_threshold { return $_[0]->{threshold} }
lib/Algorithm/Classifier/IsolationForest.pm view on Meta::CPAN
unless ref $data eq 'ARRAY' && @$data;
my @rows;
for my $i ( 0 .. $#$data ) {
push @rows, $self->tagged_row_to_array( $data->[$i], "fit_tagged (row $i)" );
}
return $self->fit( \@rows );
} ## end sub fit_tagged
=head2 pack_data(\@data)
Returns an opaque, blessed wrapper around the input dataset that the
scoring methods can use directly, skipping the per-call work of walking
the arrayref-of-arrayrefs and converting each cell into a double. At
high feature counts this is a meaningful win when the same dataset is
scored repeatedly (e.g. interactive threshold tuning, dashboards,
plotting that updates as parameters change).
Requires the Inline::C backend; croaks if C<use_c> is false.
my $packed = $forest->pack_data(\@data);
lib/Algorithm/Classifier/IsolationForest.pm view on Meta::CPAN
_use_openmp => $HAS_OPENMP,
_use_openmp_fit => 0, # opt-in only; loaded models never re-fit implicitly
};
croak "model contains no trees" unless @{ $self->{trees} };
# Recompute the normalising constant from the (integer, exact) sub-sample
# size rather than trusting the stored float, so a reloaded model's scores
# are bit-for-bit identical to the original's.
$self->{c_psi} = _c( $self->{psi_used} ) if defined $self->{psi_used};
my $model = bless $self, $class;
$model->_rebuild_c_trees() if $self->{_use_c};
return $model;
} ## end sub from_json
=head2 save($path)
Saves the model to the specified path.
$iforest->save($path);
lib/Algorithm/Classifier/IsolationForest.pm view on Meta::CPAN
}
return \@trees;
} ## end sub _unpack_forest
#-------------------------------------------------------------------------------
# Packed input wrapper. pack_data() returns one of these so callers can
# score the same dataset many times without re-walking the AV/AV refs on
# every call -- a meaningful win at high feature counts where
# pack_input_xs is a non-trivial slice of total scoring time.
#
# It's a minimal blessed hashref: { packed, n_pts, n_feats }. The C
# scoring functions only need the packed bytes + dimensions.
#-------------------------------------------------------------------------------
sub pack_data {
my ( $self, $data ) = @_;
$self->_check_fitted;
croak "pack_data requires the Inline::C backend; install Inline::C"
unless $self->{_use_c};
croak "pack_data() expects an arrayref of samples"
unless ref $data eq 'ARRAY';
my $n_pts = scalar @$data;
my $nf = $self->{n_features};
my $x_packed = "\0" x ( $n_pts * $nf * 8 );
my ( $mode, $fill ) = $self->_pack_args;
pack_input_xs( $data, $x_packed, $n_pts, $nf, $mode, $fill );
return bless {
packed => $x_packed,
n_pts => $n_pts,
n_feats => $nf,
},
'Algorithm::Classifier::IsolationForest::PackedData';
} ## end sub pack_data
# Internal helper: given $data that may be a raw arrayref OR a PackedData
# instance, return the (n_pts, n_feats, x_packed) triple ready for
# score_all_xs. Called from every scoring fast path.
lib/Algorithm/Classifier/IsolationForest/App/Command/predict.pm view on Meta::CPAN
my $score_input; # what we hand to score_predict_samples
if ( Algorithm::Classifier::IsolationForest::App::Command::pack::is_packed_file( $opt->{'i'} ) ) {
my ( $n_pts, $n_feats, $bytes )
= Algorithm::Classifier::IsolationForest::App::Command::pack::read_packed_file( $opt->{'i'} );
die "packed input has $n_feats features but model expects " . $iforest->{n_features} . "\n"
if $n_feats != $iforest->{n_features};
# Build a PackedData wrapper directly from the on-disk bytes --
# no CSV parse, no pack_input_xs.
$score_input = bless {
packed => $bytes,
n_pts => $n_pts,
n_feats => $n_feats,
},
'Algorithm::Classifier::IsolationForest::PackedData';
# Only unpack to per-row arrayrefs when -d asks for it, since
# that work undoes the whole point of using a packed file.
if ( $opt->{'d'} ) {
my @doubles = unpack( 'd*', $bytes );
lib/Algorithm/Classifier/IsolationForest/Online.pm view on Meta::CPAN
croak "subsample must be in (0, 1]"
unless $self->{subsample} > 0 && $self->{subsample} <= 1;
croak "contamination must be a number in (0, 0.5]"
if defined $self->{contamination}
&& !( $self->{contamination} > 0 && $self->{contamination} <= 0.5 );
$self->{trees} = [ map { { root => undef, count => 0, depth_limit => 0 } } 1 .. $self->{n_trees} ];
srand( $self->{seed} ) if defined $self->{seed};
return bless $self, $class;
} ## end sub new
=head2 learn(\@data)
Learns the passed samples, in order, as the next points of the stream.
Once the model has seen more than C<window_size> points, each learned
point also forgets the oldest retained point, so the model tracks the
most recent C<window_size> points.
The data format matches the parent class's C<fit>: an arrayref of
lib/Algorithm/Classifier/IsolationForest/Online.pm view on Meta::CPAN
seen => $p->{seen} // 0,
window => $payload->{window} // [],
trees => [],
_use_c => $Algorithm::Classifier::IsolationForest::HAS_C,
_use_openmp => $Algorithm::Classifier::IsolationForest::HAS_OPENMP,
};
my $trees = $payload->{trees};
croak "model contains no trees" unless ref $trees eq 'ARRAY' && @$trees;
my $model = bless $self, $class;
# depth_limit is a pure function of the tree's count, so recompute it
# rather than trusting a stored float.
$self->{trees}
= [ map { { count => $_->{count}, root => $_->{root}, depth_limit => $model->_rpl( $_->{count} ) } } @$trees ];
return $model;
} ## end sub from_json
=head2 save($path)
( run in 0.601 second using v1.01-cache-2.11-cpan-0b5f733616e )