Algorithm-Classifier-IsolationForest

 view release on metacpan or  search on metacpan

lib/Algorithm/Classifier/IsolationForest.pm  view on Meta::CPAN

	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)"

lib/Algorithm/Classifier/IsolationForest/App/Command/fit.pm  view on Meta::CPAN

} ## end sub validate

sub execute {
	my ( $self, $opt, $args ) = @_;

	my $mode = 'axis';
	if ( $opt->{'extended'} ) {
		$mode = 'extended';
	}

	# Munger spec, decoded up front so a bad file dies before the CSV is
	# read.  With mungers active the per-field numeric check is skipped
	# during the read (munged columns legitimately hold raw strings) and
	# re-run after munging instead.
	my $mungers;
	if ( defined( $opt->{'mungers'} ) ) {
		require JSON::PP;
		$mungers = eval { JSON::PP->new->decode( scalar read_file( $opt->{'mungers'} ) ) };
		die( '--mungers, "' . $opt->{'mungers'} . '", did not parse as JSON: ' . $@ ) if $@;
		die( '--mungers, "' . $opt->{'mungers'} . '", must be a JSON object of tag => spec' )
			unless ref $mungers eq 'HASH';

lib/Algorithm/Classifier/IsolationForest/App/Command/streamc.pm  view on Meta::CPAN

	# -o accumulates and writes atomically at the end (matching `iforest
	# stream`), so it is unsuitable for an endless stdin; without it,
	# results print as replies arrive.
	my $results = '';
	my $emit    = sub {
		if ( defined $opt->{'o'} ) { $results .= $_[0] . "\n" }
		else                       { print $_[0] . "\n" }
	};

	my $expected_cols;
	my @rows;               # decoded rows for the pending request
	my @raw;                # matching raw input lines, for -d
	my $batch_start = 1;    # input line number of $rows[0]
	my $line_int    = 0;

	my $flush = sub {
		return unless @rows;
		my $got   = _request( { rows => [@rows], mode => $opt->{'mode'}, tag => $batch_start } );
		my $reply = $got->{reply};
		if ( defined $reply->{error} ) {
			my $line = $batch_start;

t/42-prototype.t  view on Meta::CPAN

	);
}; ## end 'load_prototype and persistence of the schema metadata' => sub

subtest 'to_prototype extraction round trip' => sub {
	my $data = do { srand(13); rows(150) };

	my $a = $batch_class->new_from_prototype( proto_batch(), seed => 42, contamination => 0.1 );
	$a->fit($data);

	my $extracted = $a->to_prototype;
	my $decoded   = $batch_class->validate_prototype($extracted);
	is( $decoded->{class},                 'batch', 'extracted prototype is valid and batch' );
	is( $decoded->{schema_version},        'b1',    'extracted prototype keeps the schema_version' );
	is( $decoded->{params}{contamination}, 0.1,     'override made it into the extracted params' );

	# Recreate from the extraction with the same seed: identical model.
	my $b = $batch_class->new_from_prototype( $extracted, seed => 42 );
	$b->fit($data);
	is( $b->to_json, $a->to_json, 'model recreated from the extracted prototype is byte-identical' );

	# Online extraction round-trips through the validator too.
	my $o  = $batch_class->new_from_prototype( proto_online() );
	my $op = $batch_class->validate_prototype( $o->to_prototype );
	is( $op->{class},               'online', 'online extraction carries class online' );

t/91-streamd.t  view on Meta::CPAN

		my $left = $deadline - time;
		return undef if $left <= 0 || !$sel->can_read($left);
		my $got = sysread( $s, my $chunk, 65536 );
		return undef unless $got;
		$$buf .= $chunk;
	}
	$$buf =~ s/\A([^\n]*)\n//;
	return $JSON->decode($1);
} ## end sub read_reply

# One request in, one decoded reply out.
sub rt {
	my ( $s, $msg ) = @_;
	print {$s} $JSON->encode($msg) . "\n";
	return read_reply($s);
}

my $daemon = start_daemon(
	'--save-interval' => 1,
	'-n'              => 20,
	'--window'        => 64,



( run in 0.940 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )