view release on metacpan or search on metacpan
lib/Algorithm/Classifier/NaiveBayes/App/Command/classify.pm view on Meta::CPAN
nb_tool classify -m model.json cheap pills for sale
cat some_message.txt | nb_tool classify -m model.json -p
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
return 1;
}
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
$nb->load( $opt->{'m'} );
lib/Algorithm/Classifier/NaiveBayes/App/Command/explain.pm view on Meta::CPAN
over the runner up.
nb_tool explain -m model.json you have won a free cruise
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
return 1;
}
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
$nb->load( $opt->{'m'} );
lib/Algorithm/Classifier/NaiveBayes/App/Command/info.pm view on Meta::CPAN
return 'Show the settings, classes, and stats for a saved model.
nb_tool info -m model.json
';
}
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
return 1;
}
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
$nb->load( $opt->{'m'} );
lib/Algorithm/Classifier/NaiveBayes/App/Command/prune.pm view on Meta::CPAN
# remove all tokens only trained once
nb_tool prune -m model.json 2
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
if ( !defined( $args->[0] ) ) {
$self->usage_error('No min count specified');
}
if ( $args->[0] !~ /\A\d+\z/ || $args->[0] < 1 ) {
$self->usage_error( 'The min count, "' . $args->[0] . '", is not a whole number greater than 0' );
}
return 1;
} ## end sub validate
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
$nb->load( $opt->{'m'} );
lib/Algorithm/Classifier/NaiveBayes/App/Command/tokens.pm view on Meta::CPAN
nb_tool tokens -m model.json spam
nb_tool tokens -m model.json -c spam
';
}
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
if ( !defined( $args->[0] ) ) {
$self->usage_error('No class specified');
}
return 1;
} ## end sub validate
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
$nb->load( $opt->{'m'} );
lib/Algorithm/Classifier/NaiveBayes/App/Command/train.pm view on Meta::CPAN
model file does not exist yet, as they are stored in the model.
';
} ## end sub description
my @new_args = ( 'token_splitter', 'stop_regex', 'smoothing', 'alpha', 'ngrams', 'token_weighting', 'priors' );
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !defined( $opt->{'c'} ) ) {
$self->usage_error('-c has not been specified');
}
if ( defined( $opt->{'f'} ) ) {
if ( @{$args} ) {
$self->usage_error('-f and text args may not be used together');
}
if ( !-f $opt->{'f'} ) {
$self->usage_error( '-f, "' . $opt->{'f'} . '", is not a file or does not exist' );
} elsif ( !-r $opt->{'f'} ) {
$self->usage_error( '-f, "' . $opt->{'f'} . '", is not readable' );
}
} ## end if ( defined( $opt->{'f'} ) )
if ( -f $opt->{'m'} ) {
foreach my $new_arg ( @new_args, 'no_lc' ) {
if ( defined( $opt->{$new_arg} ) ) {
my $flag = $new_arg;
$flag =~ s/_/-/g;
$self->usage_error( '--' . $flag . ' may only be used when creating a new model file' );
}
}
}
return 1;
} ## end sub validate
sub execute {
my ( $self, $opt, $args ) = @_;
lib/Algorithm/Classifier/NaiveBayes/App/Command/tweak.pm view on Meta::CPAN
nb_tool tweak -m model.json --smoothing lidstone --alpha 0.1
nb_tool tweak -m model.json --priors uniform
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
if ( !defined( $opt->{'smoothing'} ) && !defined( $opt->{'alpha'} ) && !defined( $opt->{'priors'} ) ) {
$self->usage_error('Nothing to change... at least one of --smoothing, --alpha, or --priors is needed');
}
return 1;
} ## end sub validate
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
$nb->load( $opt->{'m'} );
lib/Algorithm/Classifier/NaiveBayes/App/Command/untrain.pm view on Meta::CPAN
nb_tool untrain -m model.json -c spam something that is not spam
nb_tool untrain -m model.json -c spam -f some_ham.txt
cat ham | nb_tool untrain -m model.json -c spam
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
if ( !defined( $opt->{'c'} ) ) {
$self->usage_error('-c has not been specified');
}
if ( !-f $opt->{'m'} ) {
$self->usage_error( '-m, "' . $opt->{'m'} . '", is not a file or does not exist' );
}
if ( defined( $opt->{'f'} ) ) {
if ( @{$args} ) {
$self->usage_error('-f and text args may not be used together');
}
if ( !-f $opt->{'f'} ) {
$self->usage_error( '-f, "' . $opt->{'f'} . '", is not a file or does not exist' );
} elsif ( !-r $opt->{'f'} ) {
$self->usage_error( '-f, "' . $opt->{'f'} . '", is not readable' );
}
} ## end if ( defined( $opt->{'f'} ) )
return 1;
} ## end sub validate
sub execute {
my ( $self, $opt, $args ) = @_;
my $nb = Algorithm::Classifier::NaiveBayes->new;
t/07-save-load.t view on Meta::CPAN
is( $loaded->classify('buy cheap pills'), 'spam', 'loaded model classifies' );
# qr// Regexps are stringified on save
my $qr_nb = Algorithm::Classifier::NaiveBayes->new( 'stop_regex' => qr/at|a/ );
$qr_nb->train( 'ham', 'cat at a noon' );
$qr_nb->save($save_file);
my $qr_loaded = Algorithm::Classifier::NaiveBayes->new;
$qr_loaded->load($save_file);
is_deeply( [ $qr_loaded->tokenize('cat at a noon') ], [ 'cat', 'noon' ], 'qr// stop_regex survives save/load' );
# error handling
eval { $nb->save(); };
like( $@, qr/No file specified/, 'save with no file dies' );
eval { $nb->save( $dir . '/nonexistent/model.json' ); };
like( $@, qr/Failed to write/, 'save to an unwritable path dies' );
eval { $loaded->load(); };
like( $@, qr/No file specified/, 'load with no file dies' );
eval { $loaded->load( $dir . '/nonexistent.json' ); };
my $app = 'Algorithm::Classifier::NaiveBayes::App';
my $dir = File::Temp::tempdir( 'CLEANUP' => 1 );
my $model = $dir . '/model.json';
##
## train
##
my $result = test_app( $app => [ 'train', '-m', $model, '-c', 'spam', 'buy', 'cheap', 'pills', 'now' ] );
is( $result->error, undef, 'train runs' );
like( $result->stdout, qr/Trained "spam", 1 total documents/, 'train reports what it did' );
ok( -f $model, 'train creates the model file' );
$result = test_app( $app => [ 'train', '-m', $model, '-c', 'ham', 'meeting', 'at', 'noon', 'tomorrow' ] );
is( $result->error, undef, 'training a second class works' );
like( $result->stdout, qr/2 total documents/, 'total documents incremented' );
# creation only options are rejected on an existing model
$result = test_app( $app => [ 'train', '-m', $model, '-c', 'spam', '--ngrams', '2', 'foo' ] );
like( $result->error, qr/only be used when creating/, 'creation options rejected on a existing model' );
# missing -c
$result = test_app( $app => [ 'train', '-m', $model, 'foo' ] );
like( $result->error, qr/-c has not been specified/, 'train without -c errors' );
# -f reads the text from a file
my $text_file = $dir . '/text.txt';
open( my $fh, '>', $text_file ) or die($!);
print $fh "cheap watches for sale\n";
close($fh);
$result = test_app( $app => [ 'train', '-m', $model, '-c', 'spam', '-f', $text_file ] );
is( $result->error, undef, 'train -f runs' );
like( $result->stdout, qr/3 total documents/, 'train -f trained the document' );
$result = test_app( $app => [ 'train', '-m', $model, '-c', 'spam', '-f', $text_file, 'extra', 'args' ] );
like( $result->error, qr/-f and text args may not be used together/, 'train -f with text args errors' );
$result = test_app( $app => [ 'train', '-m', $model, '-c', 'spam', '-f', $dir . '/nonexistent.txt' ] );
like( $result->error, qr/is not a file or does not exist/, 'train -f with a missing file errors' );
$result = test_app( $app => [ 'untrain', '-m', $model, '-c', 'spam', '-f', $text_file ] );
is( $result->error, undef, 'untrain -f runs' );
like( $result->stdout, qr/2 total documents/, 'untrain -f untrained the document' );
$result = test_app( $app => [ 'untrain', '-m', $model, '-c', 'spam', '-f', $text_file, 'extra' ] );
like( $result->error, qr/-f and text args may not be used together/, 'untrain -f with text args errors' );
##
## classify
##
$result = test_app( $app => [ 'classify', '-m', $model, 'cheap', 'pills' ] );
is( $result->error, undef, 'classify runs' );
like( $result->stdout, qr/\Aspam\n/, 'classify prints the class' );
$result = test_app( $app => [ 'classify', '-m', $model, '-s', '-p', 'cheap', 'pills' ] );
like( $result->stdout, qr/scores:/, '-s prints scores' );
like( $result->stdout, qr/probs:/, '-p prints probs' );
$result = test_app( $app => [ 'classify', '-m', $model, '--json', 'cheap', 'pills' ] );
like( $result->stdout, qr/"class"\s*:\s*"spam"/, '--json prints JSON' );
$result = test_app( $app => [ 'classify', '-m', $dir . '/nonexistent.json', 'foo' ] );
like( $result->error, qr/is not a file or does not exist/, 'classify with a missing model errors' );
##
## explain
##
$result = test_app( $app => [ 'explain', '-m', $model, 'cheap', 'meeting', 'pills' ] );
is( $result->error, undef, 'explain runs' );
like( $result->stdout, qr/spam, probability/, 'explain prints the class and probability' );
like( $result->stdout, qr/cheap pushed towards spam/, 'explain prints token pulls' );
##
## info
##
$result = test_app( $app => [ 'info', '-m', $model ] );
is( $result->error, undef, 'info runs' );
like( $result->stdout, qr/total_docs: 2/, 'info prints total_docs' );
like( $result->stdout, qr/spam: docs=1/, 'info prints per class stats' );
like( $result->stdout, qr/smoothing: laplace/, 'info prints settings' );
##
## tokens
##
$result = test_app( $app => [ 'tokens', '-m', $model, 'spam' ] );
is( $result->error, undef, 'tokens runs' );
like( $result->stdout, qr/^cheap$/m, 'tokens lists the class tokens' );
$result = test_app( $app => [ 'tokens', '-m', $model, '-c', 'spam' ] );
like( $result->stdout, qr/^cheap: 1$/m, 'tokens -c includes counts' );
$result = test_app( $app => [ 'tokens', '-m', $model ] );
like( $result->error, qr/No class specified/, 'tokens without a class errors' );
##
## prune
##
$result = test_app( $app => [ 'prune', '-m', $model, '2' ] );
is( $result->error, undef, 'prune runs' );
like( $result->stdout, qr/Pruned 8 tokens, 0 remaining/, 'prune reports what it did' );
$result = test_app( $app => [ 'prune', '-m', $model, 'x' ] );
like( $result->error, qr/not a whole number/, 'prune with a bad min count errors' );
##
## tweak
##
$result = test_app( $app => [ 'tweak', '-m', $model, '--smoothing', 'lidstone', '--alpha', '0.1' ] );
is( $result->error, undef, 'tweak runs' );
like( $result->stdout, qr/smoothing: lidstone/, 'tweak reports the smoothing' );
like( $result->stdout, qr/alpha: 0.1/, 'tweak reports the alpha' );
$result = test_app( $app => [ 'info', '-m', $model ] );
like( $result->stdout, qr/smoothing: lidstone/, 'tweak changes are saved to the model' );
$result = test_app( $app => [ 'tweak', '-m', $model, '--priors', 'uniform' ] );
is( $result->error, undef, 'tweak priors runs' );
like( $result->stdout, qr/alpha: 0.1/, 'tweaking priors leaves alpha alone' );
$result = test_app( $app => [ 'tweak', '-m', $model ] );
like( $result->error, qr/Nothing to change/, 'tweak with nothing to change errors' );
$result = test_app( $app => [ 'tweak', '-m', $model, '--smoothing', 'derp' ] );
like( $result->error, qr/smoothing must be either/, 'tweak with a bad smoothing errors' );
##
## untrain
##
$result = test_app( $app => [ 'untrain', '-m', $model, '-c', 'ham', 'meeting', 'at', 'noon', 'tomorrow' ] );
is( $result->error, undef, 'untrain runs' );
like( $result->stdout, qr/Untrained "ham", 1 total documents/, 'untrain reports what it did' );
$result = test_app( $app => [ 'info', '-m', $model ] );
unlike( $result->stdout, qr/ham: docs/, 'untrained class no longer listed by info' );
done_testing;