Algorithm-Classifier-IsolationForest

 view release on metacpan or  search on metacpan

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

		$self->usage_error( '-i, "' . $opt->{'i'} . '", is not a file' );
	} elsif ( !-r $opt->{'i'} ) {
		$self->usage_error( '-i, "' . $opt->{'i'} . '", is not readable' );
	}

	if ( defined( $opt->{'s'} ) && $opt->{'s'} <= 0 ) {
		$self->usage_error( '-s, "' . $opt->{'s'} . '", is less than or equal to 0, should be a positive int' );
	}

	if ( !defined( $opt->{'extended'} ) && defined( $opt->{'e'} ) ) {
		$self->usage_error('-e may not be used without --extended');
	}

	if ( !$opt->{'p'} ) {
		if ( -e $opt->{'o'} && !$opt->{'w'} ) {
			$self->usage_error( '-o,"' . $opt->{'o'} . '", already exists and -w was not specified' );
		}
	}

	if ( defined( $opt->{'e'} ) && $opt->{'e'} < 0 ) {
		$self->usage_error( '-e, "' . $opt->{'e'} . '", is less than 0... should be a float greater or equal to 0' );
	}

	if ( defined( $opt->{'voting'} ) && $opt->{'voting'} !~ /\A(?:mean|majority)\z/ ) {
		$self->usage_error( '--voting, "' . $opt->{'voting'} . '", must be either mean or majority' );
	}

	if ( defined( $opt->{'mungers'} ) ) {
		if ( !-f $opt->{'mungers'} ) {
			$self->usage_error( '--mungers, "' . $opt->{'mungers'} . '", is not a file or does not exist' );
		} elsif ( !-r $opt->{'mungers'} ) {
			$self->usage_error( '--mungers, "' . $opt->{'mungers'} . '", is not readable' );
		} elsif ( !defined( $opt->{'t'} ) ) {
			$self->usage_error('--mungers requires feature tags (-t) to compile against');
		}
	}

	if ( defined( $opt->{'prototype'} ) ) {
		if ( !-f $opt->{'prototype'} ) {
			$self->usage_error( '--prototype, "' . $opt->{'prototype'} . '", is not a file or does not exist' );
		} elsif ( !-r $opt->{'prototype'} ) {
			$self->usage_error( '--prototype, "' . $opt->{'prototype'} . '", is not readable' );
		}
		if ( defined( $opt->{'t'} ) || defined( $opt->{'mungers'} ) ) {
			$self->usage_error(
				'--prototype may not be combined with -t or --mungers; the schema comes only from the prototype');
		}
	} ## end if ( defined( $opt->{'prototype'} ) )

	return 1;
} ## 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';
	}

	# A prototype supplies the schema and knob defaults, so the model is
	# created before the CSV is read (a munger-bearing prototype changes
	# how the CSV is validated).  Explicit tuning switches override the
	# prototype's params; the schema may not be overridden at all.
	my $iforest;
	if ( defined( $opt->{'prototype'} ) ) {
		my $proto = eval {
			Algorithm::Classifier::IsolationForest->validate_prototype( scalar read_file( $opt->{'prototype'} ) );
		};
		die( '--prototype, "' . $opt->{'prototype'} . '", is not a valid prototype: ' . $@ ) if $@;
		die( '--prototype, "' . $opt->{'prototype'} . '", is for an online model; use `iforest stream`' . "\n" )
			unless $proto->{class} eq 'batch';

		my %overrides;
		$overrides{'n_trees'}         = $opt->{'n'}      if defined $opt->{'n'};
		$overrides{'seed'}            = $opt->{'s'}      if defined $opt->{'s'};
		$overrides{'sample_size'}     = $opt->{'m'}      if defined $opt->{'m'};
		$overrides{'max_depth'}       = $opt->{'d'}      if defined $opt->{'d'};
		$overrides{'mode'}            = 'extended'       if $opt->{'extended'};
		$overrides{'extension_level'} = $opt->{'e'}      if defined $opt->{'e'};
		$overrides{'contamination'}   = $opt->{'c'}      if defined $opt->{'c'};
		$overrides{'voting'}          = $opt->{'voting'} if defined $opt->{'voting'};

		$iforest = eval { Algorithm::Classifier::IsolationForest->new_from_prototype( $proto, %overrides ) };
		die( '--prototype, "' . $opt->{'prototype'} . '", failed to create a model: ' . $@ ) if $@;
	} ## end if ( defined( $opt->{'prototype'} ) )

	my $has_mungers
		= $mungers                                                                      ? 1
		: ( $iforest && ref $iforest->{mungers} eq 'HASH' && %{ $iforest->{mungers} } ) ? 1
		:                                                                                 0;

	my @data;
	my $expected_cols;

	my $line_int = 1;
	foreach my $line ( read_file( $opt->{'i'} ) ) {
		chomp($line);
		next if $line =~ /^\s*$/;

		my @fields = split( /,/, $line, -1 );

		if ( !defined($expected_cols) ) {
			$expected_cols = scalar @fields;
			die( 'Line ' . $line_int . ' of "' . $opt->{'i'} . '" has no columns' )
				if $expected_cols < 1;
		} elsif ( scalar @fields != $expected_cols ) {
			die(      'Line '



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