Algorithm-Classifier-IsolationForest

 view release on metacpan or  search on metacpan

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

	} ## end if ( !$oif )

	# Munge the raw rows into numbers, then run the numeric validation
	# that was skipped at read time.  Munged into a separate structure so
	# -d still prints the raw input columns as given.
	my $stream_rows = \@data;
	if ($has_mungers) {
		my $munged = $oif->munge_rows( \@data );
		for my $i ( 0 .. $#$munged ) {
			for my $col ( 0 .. $#{ $munged->[$i] } ) {
				die(      'Line '
						. ( $i + 1 ) . ' of "'
						. $opt->{'i'}
						. '" value for column '
						. ( $col + 1 ) . ',"'
						. ( defined $munged->[$i][$col] ? $munged->[$i][$col] : 'undef' )
						. '", is not a number after munging' )
					unless looks_like_number( $munged->[$i][$col] );
			} ## end for my $col ( 0 .. $#{ $munged->[$i] } )
		} ## end for my $i ( 0 .. $#$munged )
		$stream_rows = $munged;
	} ## end if ($has_mungers)

	# --- stream ------------------------------------------------------------
	my $results_string = '';
	if ( $opt->{'learn_only'} ) {
		$oif->learn($stream_rows);
	} else {
		my $scores;
		if ( $opt->{'score_only'} ) {
			$scores = $oif->score_samples($stream_rows);
		} else {
			$scores = $oif->score_learn($stream_rows);
		}

		my $threshold
			= defined $opt->{'threshold'}      ? $opt->{'threshold'}
			: defined $oif->decision_threshold ? $oif->decision_threshold
			:                                    0.5;

		for my $i ( 0 .. $#$scores ) {
			my $label = $scores->[$i] >= $threshold ? 1 : 0;
			if ( $opt->{'d'} ) {
				$results_string .= join( ',', @{ $data[$i] } ) . ',' . $scores->[$i] . ',' . $label . "\n";
			} else {
				$results_string .= $scores->[$i] . ',' . $label . "\n";
			}
		}
	} ## end else [ if ( $opt->{'learn_only'} ) ]

	# Refresh the contamination threshold against the post-stream window so
	# the saved model's default cutoff tracks the stream.
	if ( !$opt->{'score_only'} && defined $oif->{contamination} && $oif->window_count ) {
		$oif->relearn_threshold;
	}

	if ( $opt->{'save'} && !$opt->{'score_only'} ) {
		$oif->save( $opt->{'m'} );
	}

	if ( length $results_string ) {
		if ( !defined( $opt->{'o'} ) ) {
			print $results_string;
		} else {
			write_file( $opt->{'o'}, { 'atomic' => 1 }, $results_string );
		}
	}

	return 1;
} ## end sub execute

=head1 NAME

Algorithm::Classifier::IsolationForest::App::Command::stream - Stream CSV rows through an Online Isolation Forest model, scoring and learning as it goes

=head1 DESCRIPTION

Streams the input rows, in order, through an
L<Algorithm::Classifier::IsolationForest::Online> model.

The default is prequential: each row is scored against the model as it
stood before that row was learned, then learned, and the model state --
sliding window included -- is saved back to C<-m>, so the next invocation
resumes the stream where this one left off.  C<--learn-only> skips the
scoring, which is what a warm-up wants; C<--score-only> skips the
learning.

When C<-m> does not exist yet the creation knobs build a new model; when
it does exist they are ignored.  With C<--prototype> the schema and its
version and description come from the prototype file, its params supply
the knob defaults, and the other creation switches override those params.

Input matches C<iforest fit>: CSV, every column a numeric feature, one
sample per row.  Output is one line per input row:

  $score,$label

With C<-d> the input feature columns are prepended.

Run it as C<iforest stream>; C<iforest help stream> lists every option.

=head1 METHODS

L<App::Cmd> calls these while dispatching the subcommand.  Nothing else
should.

=head2 opt_spec

Returns this command's option specifications, as the list of arrayrefs
L<Getopt::Long::Descriptive> expects.

=head2 abstract

Returns the one-line summary C<iforest commands> prints beside the
command name.

=head2 description

Returns the long help text C<iforest help stream> prints under the option
list.



( run in 2.284 seconds using v1.01-cache-2.11-cpan-54e63673c56 )