Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
lib/Algorithm/Classifier/IsolationForest.pm view on Meta::CPAN
}
The fields, top to bottom...
- format :: required, always the string
'Algorithm::Classifier::IsolationForest::Prototype'. A prototype
handed to load() (or a model handed to the prototype methods)
dies with a clear message instead of half-working.
- version :: the prototype format version; this release reads version 1.
default :: 1
- class :: required, 'batch' (this class) or 'online'
(L<Algorithm::Classifier::IsolationForest::Online>). Prototypes
are self-describing; `iforest fit` refuses an online prototype
and `iforest stream` refuses a batch one. Two model types with
the same variables means two prototype files.
- schema_version :: required opaque string, never parsed or compared
numerically. User-owned: bump it when the variable schema
changes.
- schema_description :: required opaque free-text string describing
what this variable schema is, so a model file explains itself
months later.
- schema :: required object holding the variable schema.
feature_names is required (order = CSV column order); the
optional keys are feature_descriptions ('feature name => free
text', every key must name an entry in feature_names, partial
coverage fine), mungers (see L</MUNGERS>), missing, and -- batch
prototypes only -- impute_with. Unknown keys croak.
- params :: optional object of tuning knobs, whitelisted per class.
Batch: n_trees, sample_size, max_depth, mode, extension_level,
contamination, voting, seed. Online: n_trees, window_size,
max_leaf_samples, growth, subsample, contamination, seed.
Unknown keys croak -- a typo'd knob silently falling back to its
default is exactly the failure mode a prototype exists to
prevent. Machine-local knobs (use_c, use_openmp, use_openmp_fit,
parallel_fit) are rejected: they describe the box the model runs
on, not the model.
=cut
# Per-class whitelists for a prototype's params block (and
# new_from_prototype's %overrides) and its schema block. Machine-local
# knobs are deliberately absent from the params lists.
my %PROTO_PARAM_KEYS = (
batch => { map { $_ => 1 } qw(n_trees sample_size max_depth mode extension_level contamination voting seed) },
online => { map { $_ => 1 } qw(n_trees window_size max_leaf_samples growth subsample contamination seed) },
);
my %PROTO_SCHEMA_KEYS = (
batch => { map { $_ => 1 } qw(feature_names feature_descriptions mungers missing impute_with) },
online => { map { $_ => 1 } qw(feature_names feature_descriptions mungers missing) },
);
=head2 validate_prototype($proto)
Structurally validates a prototype -- a hashref or a JSON string -- and
returns the decoded hashref; croaks describing the first problem found.
Validation is structural only (no munger compilation), so it does not
require Algorithm::ToNumberMunger even for a munger-bearing prototype.
my $proto = Algorithm::Classifier::IsolationForest->validate_prototype($json);
=cut
sub validate_prototype {
my ( $class, $proto ) = @_;
if ( !ref $proto ) {
my $decoded = eval { JSON::PP->new->decode($proto) };
croak "prototype did not parse as JSON: $@" if $@;
$proto = $decoded;
}
croak "not an IsolationForest prototype (expected a JSON object)"
unless ref $proto eq 'HASH';
croak "not an IsolationForest prototype (format is not " . "'Algorithm::Classifier::IsolationForest::Prototype')"
unless defined $proto->{format}
&& !ref $proto->{format}
&& $proto->{format} eq 'Algorithm::Classifier::IsolationForest::Prototype';
my $version = $proto->{version} // 1;
croak "prototype format version '$version' is newer than this module understands (max 1)"
if !ref $version && $version =~ /^\d+$/ && $version > 1;
for my $k ( sort keys %$proto ) {
croak "prototype has unknown top-level key '$k'"
unless $k =~ /\A(?:format|version|class|schema_version|schema_description|schema|params)\z/;
}
my $which = $proto->{class};
croak "prototype needs a class of 'batch' or 'online'"
unless defined $which && !ref $which && $which =~ /\A(?:batch|online)\z/;
for my $req (qw(schema_version schema_description)) {
croak "prototype needs a non-empty $req string"
unless defined $proto->{$req} && !ref $proto->{$req} && length $proto->{$req};
}
my $schema = $proto->{schema};
croak "prototype needs a schema object" unless ref $schema eq 'HASH';
for my $k ( sort keys %$schema ) {
croak "prototype schema has unknown key '$k' for a $which prototype (allowed: "
. join( ', ', sort keys %{ $PROTO_SCHEMA_KEYS{$which} } ) . ')'
unless $PROTO_SCHEMA_KEYS{$which}{$k};
}
my $tags = $schema->{feature_names};
croak "prototype schema needs a non-empty feature_names array"
unless ref $tags eq 'ARRAY' && @$tags;
for my $t (@$tags) {
croak "prototype feature_names entries must be non-empty strings"
unless defined $t && !ref $t && length $t;
}
_validate_feature_descriptions( $tags, $schema->{feature_descriptions} )
if defined $schema->{feature_descriptions};
croak "prototype schema mungers must be an object of 'tag => munger spec'"
if defined $schema->{mungers} && ref $schema->{mungers} ne 'HASH';
for my $str (qw(missing impute_with)) {
croak "prototype schema $str must be a plain string"
if defined $schema->{$str} && ref $schema->{$str};
}
my $params = $proto->{params};
croak "prototype params must be an object of tuning knobs"
if defined $params && ref $params ne 'HASH';
for my $k ( sort keys %{ $params || {} } ) {
croak "prototype params has unknown key '$k' for a $which prototype (allowed: "
. join( ', ', sort keys %{ $PROTO_PARAM_KEYS{$which} } )
. '; machine-local knobs like use_c are deliberately not allowed)'
unless $PROTO_PARAM_KEYS{$which}{$k};
}
return $proto;
( run in 1.772 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )