Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
lib/Algorithm/Classifier/IsolationForest/App/Command/csv2plot.pm view on Meta::CPAN
package Algorithm::Classifier::IsolationForest::App::Command::csv2plot;
use strict;
use warnings;
use Algorithm::Classifier::IsolationForest ();
use Algorithm::Classifier::IsolationForest::App -command;
use File::Slurp qw(read_file write_file);
use File::Spec ();
use File::Temp qw(tempfile);
sub opt_spec {
return (
[ 'i=s', 'Input CSV for processing.', { 'completion' => 'files' } ],
[ 'o=s', 'PNG file to output to. Default: plot.png', { 'default' => 'plot.png', 'completion' => 'files' } ],
[ 'w', 'If the file specified via -o exists, over write it.' ],
[
'p=s',
'Type of plot. Default: auto',
{ 'default' => 'auto', completion => [ 'auto', '2heat', '3range', '3binary' ] }
],
[ 'print', 'Print what would be used with gnuplot instead of calling gnuplot' ],
[ 'open', 'Call xdg-open to open the generated graph.' ],
[ 'small-points', 'Use smaller points (ps 0.8) for dense 3range datasets.' ],
);
} ## end sub opt_spec
sub abstract { 'Plot the CSV data used with iforest via gnuplot.' }
sub description {
'Plot the CSV data used with iforest via gnuplot.
Plot types are as below.
auto: If there are two columns, 2heat. If there are 4 or more columns, 3range.
2heat: Use column 1 and 2 to generate a splatter plot over a heat map.
3range: Use columns 1 and 2 for x/y, and the second-to-last column for the
score gradient. Suitable for predict -d output (any number of features).
3binary: Use columns 1 and 2 for x/y, and the last column for normal/abnormal.
Suitable for predict -d output or gblob output.
3range and 3binary require data outputted from predict with the -d flag.
For N-dimensional data, columns 1 and 2 are always used for the x/y axes.
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !defined( $opt->{'i'} ) ) {
$self->usage_error('-i has not been specified for a file to process');
} elsif ( !-f $opt->{'i'} ) {
$self->usage_error( '-i, "' . $opt->{'i'} . '", is not a file or does not exist' );
} elsif ( !-r $opt->{'i'} ) {
$self->usage_error( '-i, "' . $opt->{'i'} . '", is not readable' );
}
if ( -e $opt->{'o'} && !$opt->{'w'} ) {
$self->usage_error( '-o, "' . $opt->{'o'} . '", already exists and -w is not given' );
} elsif ( -e $opt->{'o'} && !-f $opt->{'o'} ) {
$self->usage_error( '-o, "' . $opt->{'o'} . '", already exists and -w given but file is not a file' );
} elsif ( -e $opt->{'o'} && !-w $opt->{'o'} ) {
$self->usage_error( '-o, "' . $opt->{'o'} . '", already exists and -w given but file is not writable' );
}
if ( ( $opt->{'p'} ne 'auto' )
&& ( $opt->{'p'} ne '2heat' )
&& ( $opt->{'p'} ne '3range' )
&& ( $opt->{'p'} ne '3binary' ) )
{
$self->usage_error( '-p, "' . $opt->{'p'} . '", is not set to auto, 2heat, 3range, or 3binary' );
}
return 1;
} ## end sub validate
sub execute {
my ( $self, $opt, $args ) = @_;
my @raw_csv = read_file( $opt->{'i'} );
my @first_fields = split( /,/, $raw_csv[0] );
my $ncols = scalar @first_fields;
if ( $opt->{'p'} eq 'auto' && $ncols >= 4 ) {
$opt->{'p'} = '3range';
} elsif ( $opt->{'p'} eq 'auto' && $ncols >= 2 ) {
$opt->{'p'} = '2heat';
} elsif ( $opt->{'p'} eq 'auto' ) {
die('-p is set to auto and the specified CSV does not have enough columns');
} elsif ( $opt->{'p'} eq '2heat' && $ncols < 2 ) {
die('2heat specified but there is no column for y');
} elsif ( $opt->{'p'} eq '3range' && $ncols < 3 ) {
die('3range specified but there is no column for score');
} elsif ( $opt->{'p'} eq '3binary' && $ncols < 3 ) {
die('3binary specified but there is no column for truth');
}
# For predict -d output: score is the second-to-last column, prediction is last.
my $score_col = $ncols - 1;
my $pred_col = $ncols;
$opt->{'i'} = File::Spec->rel2abs( $opt->{'i'} );
( run in 0.612 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )