AI-Perceptron-Simple

 view release on metacpan or  search on metacpan

docs/AI-Perceptron-Simple-1.04.html  view on Meta::CPAN

      <li><a href="#calculate_f1_score-c_matrix_ref">&amp;_calculate_f1_score ( $c_matrix_ref )</a></li>
      <li><a href="#calculate_negative_predicted_value-c_matrix_ref">&amp;_calculate_negative_predicted_value( $c_matrix_ref )</a></li>
      <li><a href="#calculate_false_negative_rate-c_matrix_ref">&amp;_calculate_false_negative_rate( $c_matrix_ref )</a></li>
      <li><a href="#calculate_false_positive_rate-c_matrix_ref">&amp;_calculate_false_positive_rate( $c_matrix_ref )</a></li>
      <li><a href="#calculate_false_discovery_rate-c_matrix_ref">&amp;_calculate_false_discovery_rate( $c_matrix_ref )</a></li>
      <li><a href="#calculate_false_omission_rate-c_matrix_ref">&amp;_calculate_false_omission_rate( $c_matrix_ref )</a></li>
      <li><a href="#calculate_balanced_accuracy-c_matrix_ref">&amp;_calculate_balanced_accuracy( $c_matrix_ref )</a></li>
      <li><a href="#display_exam_results">display_exam_results ( ... )</a></li>
      <li><a href="#display_confusion_matrix-confusion_matrix-labels">display_confusion_matrix ( \%confusion_matrix, \%labels )</a></li>
      <li><a href="#build_matrix-c_matrix-labels">&amp;_build_matrix ( $c_matrix, $labels )</a></li>
      <li><a href="#print_extended_matrix-matrix-c_matrix">&amp;_print_extended_matrix ( $matrix, $c_matrix )</a></li>
    </ul>
  </li>
  <li><a href="#NERVE-DATA-RELATED-SUBROUTINES">NERVE DATA RELATED SUBROUTINES</a>
    <ul>
      <li><a href="#preserve">preserve ( ... )</a></li>
      <li><a href="#save_perceptron-nerve-nerve_file">save_perceptron ( $nerve, $nerve_file )</a></li>
      <li><a href="#revive">revive (...)</a></li>
      <li><a href="#load_perceptron-nerve_file_to_load">load_perceptron ( $nerve_file_to_load )</a></li>
    </ul>
  </li>

docs/AI-Perceptron-Simple-1.04.html  view on Meta::CPAN

        full_data_file =&gt; $file_csv, 
        actual_output_header =&gt; $header_name,
        predicted_output_header =&gt; $predicted_header_name,
        more_stats =&gt; 1, # optional
    } );

    # accessing the confusion matrix
    my @keys = qw( true_positive true_negative false_positive false_negative 
                   total_entries accuracy sensitivity );
    for ( @keys ) {
        print $_, &quot; =&gt; &quot;, $c_matrix{ $_ }, &quot;\n&quot;;
    }

    # output to console
    $nerve-&gt;display_confusion_matrix( \%c_matrix, { 
        zero_as =&gt; &quot;bad apples&quot;, # cat  milk   green  etc.
        one_as =&gt; &quot;good apples&quot;, # dog  honey  pink   etc.
    } );


    # saving and loading data of perceptron locally

docs/AI-Perceptron-Simple-1.04.html  view on Meta::CPAN

<p>Please take note that non-ascii characters ie. non-English alphabets <b>might</b> cause the output to go off :)</p>

<p>For the <code>%labels</code>, there is no need to enter &quot;actual X&quot;, &quot;predicted X&quot; etc. It will be prefixed with <code>A: </code> for actual and <code>P: </code> for the predicted values by default.</p>

<h2 id="build_matrix-c_matrix-labels">&amp;_build_matrix ( $c_matrix, $labels )</h2>

<p>Builds the matrix using <code>Text::Matrix</code> module.</p>

<p><code>$c_matrix</code> and <code>$labels</code> are the same as the ones passed to <code>display_exam_results</code> and <code></code>display_confusion_matrix.</p>

<p>Returns a list <code>( $matrix, $c_matrix )</code> which can directly be passed to <code>_print_extended_matrix</code>.</p>

<h2 id="print_extended_matrix-matrix-c_matrix">&amp;_print_extended_matrix ( $matrix, $c_matrix )</h2>

<p>Extends and outputs the matrix on the screen.</p>

<p><code>$matrix</code> and <code>$c_matrix</code> are the same as returned by <code>&amp;_build_matrix</code>.</p>

<h1 id="NERVE-DATA-RELATED-SUBROUTINES">NERVE DATA RELATED SUBROUTINES</h1>

<p>This part is about saving the data of the nerve. These subroutines can be imported using the <code>:local_data</code> tag.</p>

<p><b>The subroutines are to be called in the procedural way</b>. No checking is done currently.</p>

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

        full_data_file => $file_csv, 
        actual_output_header => $header_name,
        predicted_output_header => $predicted_header_name,
        more_stats => 1, # optional
    } );

    # accessing the confusion matrix
    my @keys = qw( true_positive true_negative false_positive false_negative 
                   total_entries accuracy sensitivity );
    for ( @keys ) {
        print $_, " => ", $c_matrix{ $_ }, "\n";
    }

    # output to console
    $nerve->display_confusion_matrix( \%c_matrix, { 
        zero_as => "bad apples", # cat  milk   green  etc.
        one_as => "good apples", # dog  honey  pink   etc.
    } );


    # saving and loading data of perceptron locally

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

    for ( @shuffled_stimuli_names ) {
        # copied from _real_validate_or_test
        # open for shuffling
        my $aoa = csv (in => $stimuli, encoding => ":encoding(utf-8)");
        my $attrib_array_ref = shift @$aoa; # 'remove' the header, it's annoying :)
        @aoa = shuffle( @$aoa ); # this can only process actual array
        unshift @aoa, $attrib_array_ref; # put back the headers before saving file

        csv( in => \@aoa, out => $_, encoding => ":encoding(utf-8)" ) 
        and
        print "Saved shuffled data into ", basename($_), "!\n";

    }
}

=head1 CREATION RELATED SUBROUTINES/METHODS

=head2 new ( \%options )

Creates a brand new perceptron and initializes the value of each attribute / dendrite aka. weight. Think of it as the thickness or plasticity of the dendrites.

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

    open my $data_fh, "<:encoding(UTF-8)", $stimuli_train_csv 
        or croak "Can't open $stimuli_train_csv: $!";
    
    my $csv = Text::CSV->new( {auto_diag => 1, binary => 1} );
    
    my $attrib = $csv->getline($data_fh);
    $csv->column_names( $attrib );

    # individual row
    ROW: while ( my $row = $csv->getline_hr($data_fh) ) {
        # print $row->{book_name}, " -> ";
        # print $row->{$expected_output_header} ? "意林\n" : "魅丽优品\n";

        # calculate the output and fine tune parameters if necessary
        while (1) {
            my $output = _calculate_output( $self, $row );
            
            #print "Sum = ", $output, "\n";
            
            # $expected_output_header to be checked together over here
            # if output >= threshold
            #    then category/result aka output is considered 1
            # else output considered 0
            
            # output expected/actual tuning
            #    0       0             -
            #    1       0             down
            #    0       1             up
            #    1       1             -
            if ( ($output >= $self->threshold) and ( $row->{$expected_output_header} eq 0 ) ) {
                _tune( $self, $row, TUNE_DOWN );

                if ( $display_stats ) {
                    print $row->{$identifier}, "\n";
                    print "   -> TUNED DOWN";
                    print "   Old sum = ", $output;
                    print "   Threshold = ", $self->threshold;
                    print "   New Sum = ", _calculate_output( $self, $row ), "\n";                
                }
                
            } elsif ( ($output < $self->threshold) and ( $row->{$expected_output_header} eq 1 ) ) {
                _tune( $self, $row, TUNE_UP );
                
                if ( $display_stats ) {
                    print $row->{$identifier}, "\n";
                    print "   -> TUNED UP";
                    print "   Old sum = ", $output;
                    print "   Threshold = ", $self->threshold;
                    print "   New Sum = ", _calculate_output( $self, $row ), "\n";
                }

            } elsif ( ($output < $self->threshold) and ( $row->{$expected_output_header} eq 0 ) ) {
            
                if ( $display_stats ) {
                    print $row->{$identifier}, "\n";
                    print "   -> NO TUNING NEEDED";
                    print "   Sum = ", _calculate_output( $self, $row );
                    print "   Threshold = ", $self->threshold, "\n";
                }
                
                next ROW;
                
            } elsif ( ($output >= $self->threshold) and ( $row->{$expected_output_header} eq 1 ) ) {
            
                if ( $display_stats ) {
                    print $row->{$identifier}, "\n";
                    print "   -> NO TUNING NEEDED";
                    print "   Sum = ", _calculate_output( $self, $row );
                    print "   Threshold = ", $self->threshold, "\n";
                }
                
                next ROW;
            } #else { print "Something's not right\n'" }
        }
    }

    close $data_fh;
    
    save_perceptron( $self, $save_nerve_to_file ); # this doesn't return anything
    
}

=head2 &_calculate_output( $self, \%stimuli_hash )

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

    my ( $stimuli_hash_ref, $tuning_status ) = @_;

    my %dendrites = $self->get_attributes;

    for ( keys %dendrites ) {
        if ( $tuning_status == TUNE_DOWN ) {
            
            if ( $stimuli_hash_ref->{ $_ } ) { # must check this one, it must be 1 before we can alter the actual dendrite size in the nerve :)
                $self->{ attributes_hash_ref }{ $_ } -= $self->learning_rate;
            }
            #print $_, ": ", $self->{ attributes_hash_ref }{ $_ }, "\n";
            
        } elsif ( $tuning_status == TUNE_UP ) {
            
            if ( $stimuli_hash_ref->{ $_ } ) {
                $self->{ attributes_hash_ref }{ $_ } += $self->learning_rate;
            }
            #print $_, ": ", $self->{ attributes_hash_ref }{ $_ }, "\n";
            
        }
    }

}

=head1 VALIDATION RELATED METHODS

All the validation methods here have the same parameters as the actual C<validate> method and they all do the same stuff. They are also used in the same way.

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

    # open for writing results
    my $aoa = csv (in => $stimuli_validate, encoding => ":encoding(utf-8)");
    
    my $attrib_array_ref = shift @$aoa; # 'remove' the header, it's annoying :)

    $aoa = _fill_predicted_values( $self, $stimuli_validate, $predicted_index, $aoa );

    # put back the array of headers before saving file
    unshift @$aoa, $attrib_array_ref;

    print "Saving data to $output_file\n";
    csv( in => $aoa, out => $output_file, encoding => ":encoding(utf-8)" );
    print "Done saving!\n";

}

=head2 &_fill_predicted_values ( $self, $stimuli_validate, $predicted_index, $aoa )

This is where the filling in of the predicted values takes place. Take note that the parameters naming are the same as the ones used in the C<validate> and C<test> method.

This subroutine should be called in the procedural way.

=cut

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

    
    #####
    my @missing_keys;
    for ( qw( zero_as one_as ) ) {
        push @missing_keys, $_ unless exists $labels->{ $_ };
    }
    
    croak "Missing keys: @missing_keys" if @missing_keys;
    #####
    
    _print_extended_matrix ( _build_matrix( $c_matrix, $labels ) );

}

=head2 &_build_matrix ( $c_matrix, $labels )

Builds the matrix using C<Text::Matrix> module.

C<$c_matrix> and C<$labels> are the same as the ones passed to C<display_exam_results> and C<>display_confusion_matrix.

Returns a list C<( $matrix, $c_matrix )> which can directly be passed to C<_print_extended_matrix>.

=cut

sub _build_matrix {

    my ( $c_matrix, $labels ) = @_;

    my $predicted_columns = [ "P: ".$labels->{ zero_as }, "P: ".$labels->{ one_as }, "Sum" ];
    my $actual_rows = [ "A: ".$labels->{ zero_as }, "A: ".$labels->{ one_as }, "Sum"];
    

lib/AI/Perceptron/Simple.pm  view on Meta::CPAN

    ];
    my $matrix = Text::Matrix->new(
        rows => $actual_rows,
        columns => $predicted_columns,
        data => $data,
    );
    
    $matrix, $c_matrix;
}

=head2 &_print_extended_matrix ( $matrix, $c_matrix )

Extends and outputs the matrix on the screen.

C<$matrix> and C<$c_matrix> are the same as returned by C<&_build_matrix>.

=cut

sub _print_extended_matrix {

    my ( $matrix, $c_matrix ) = @_;
    
    print "~~" x24, "\n";
    print "CONFUSION MATRIX (A:actual  P:predicted)\n";
    print "~~" x24, "\n";

    print $matrix->matrix();

    print "~~" x24, "\n";
    print "Total of ", $c_matrix->{ total_entries } , " entries\n";
    print "  Accuracy: $c_matrix->{ accuracy } %\n";
    print "  Sensitivity: $c_matrix->{ sensitivity } %\n";
    # more stats
    print "  Precision: $c_matrix->{ precision } %\n" if exists $c_matrix->{ precision };
    print "  Specificity: $c_matrix->{ specificity } %\n" if exists $c_matrix->{ specificity };
    print "  F1 Score: $c_matrix->{ F1_Score } %\n" if exists $c_matrix->{ F1_Score };
    print "  Negative Predicted Value: $c_matrix->{ negative_predicted_value } %\n" if exists $c_matrix->{ negative_predicted_value };
    print "  False Negative Rate: $c_matrix->{ false_negative_rate } %\n" if exists $c_matrix->{ false_negative_rate };
    print "  False Positive Rate: $c_matrix->{ false_positive_rate } %\n" if exists $c_matrix->{ false_positive_rate };
    print "  False Discovery Rate: $c_matrix->{ false_discovery_rate } %\n" if exists $c_matrix->{ false_discovery_rate };
    print "  False Omission Rate: $c_matrix->{ false_omission_rate } %\n" if exists $c_matrix->{ false_omission_rate };
    print "  Balanced Accuracy: $c_matrix->{ balanced_accuracy } %\n" if exists $c_matrix->{ balanced_accuracy };
    print "~~" x24, "\n";
}

=head1 NERVE DATA RELATED SUBROUTINES

This part is about saving the data of the nerve. These subroutines can be imported using the C<:local_data> tag.

B<The subroutines are to be called in the procedural way>. No checking is done currently.

See C<PERCEPTRON DATA> and C<KNOWN ISSUES> sections for more details on the subroutines in this section.

t/00-load.t  view on Meta::CPAN

#!perl
use 5.006;
use strict;
use warnings;
use Test::More;

plan tests => 1;

BEGIN {
    use_ok( 'AI::Perceptron::Simple' ) || print "Bail out!\n";
}

diag( "Testing AI::Perceptron::Simple $AI::Perceptron::Simple::VERSION, Perl $], $^X" );

t/02-creation.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;

use AI::Perceptron::Simple;

my $module_name = "AI::Perceptron::Simple";
my $initial_value = 1.5;
my @attributes = qw( glossy_look has_flowers );

# print AI::Perceptron::Simple::LEARNING_RATE;

# all important parameter test
my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => $initial_value,
    attribs => \@attributes
} );

is( ref $perceptron, $module_name, "Correct object" );

# default learning_rate() threshold()

t/04-train.t  view on Meta::CPAN


my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => 0.01,
    attribs => \@attributes
} );

my %attribs = $perceptron->get_attributes; # merging will cause problems
my $perceptron_headers = keys %attribs; # scalar context directly return number of keys

is( $perceptron_headers, $total_headers, "Correct headers" );
# print $FindBin::Bin, "\n";
# print TRAINING_DATA, "\n";
ok ( -e TRAINING_DATA, "Found the training file" );

# saving and loading - this should go into a new test script
my $nerve_file = $FindBin::Bin . "/perceptron_1.nerve";
#ok( $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER ), "No problem with \'train\' method so far" );

{
local $@ = "";
eval { $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER) };
is ( $@, "", "No problem with \'train\' method (verbose) so far" );

t/04-train_synonyms_exercise.t  view on Meta::CPAN


my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => 0.01,
    attribs => \@attributes
} );

my %attribs = $perceptron->get_attributes; # merging will cause problems
my $perceptron_headers = keys %attribs; # scalar context directly return number of keys

is( $perceptron_headers, $total_headers, "Correct headers" );
# print $FindBin::Bin, "\n";
# print TRAINING_DATA, "\n";
ok ( -e TRAINING_DATA, "Found the training file" );

# saving and loading - this should go into a new test script
my $nerve_file = $FindBin::Bin . "/perceptron_exercise.nerve";
#ok( $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER ), "No problem with \'train\' method so far" );

{
local $@ = "";
eval { $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER) };
is ( $@, "", "No problem with \'train\' method (verbose) so far" );

t/04-train_synonyms_tame.t  view on Meta::CPAN


my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => 0.01,
    attribs => \@attributes
} );

my %attribs = $perceptron->get_attributes; # merging will cause problems
my $perceptron_headers = keys %attribs; # scalar context directly return number of keys

is( $perceptron_headers, $total_headers, "Correct headers" );
# print $FindBin::Bin, "\n";
# print TRAINING_DATA, "\n";
ok ( -e TRAINING_DATA, "Found the training file" );

# saving and loading - this should go into a new test script
my $nerve_file = $FindBin::Bin . "/perceptron_tame.nerve";
#ok( $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER ), "No problem with \'train\' method so far" );

{
local $@ = "";
eval { $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER) };
is ( $@, "", "No problem with \'train\' method (verbose) so far" );

t/06-validate.t  view on Meta::CPAN

my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => 0.01,
    learning_rate => 0.001,
    threshold => 0.8,
    attribs => \@attributes
} );

my $nerve_file = $FindBin::Bin . "/perceptron_1.nerve";

for ( 0..5 ) {
    print "Round $_\n";
    $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER );
    print "\n";
}
#print Dumper($perceptron), "\n";

# write ack to original file
my $ori_file_size = -s VALIDATION_DATA;
stdout_like {
    ok ( $perceptron->validate( {
                stimuli_validate => VALIDATION_DATA,
                predicted_column_index => 4,
            } ), 
            "Validate succedded!" );
} qr/book_list_validate\.csv/, "Correct output for validate when saving file";

t/06-validate_synonyms_lab.t  view on Meta::CPAN

my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => 0.01,
    learning_rate => 0.001,
    threshold => 0.8,
    attribs => \@attributes
} );

my $nerve_file = $FindBin::Bin . "/perceptron_1.nerve";

for ( 0..5 ) {
    print "Round $_\n";
    $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER );
    print "\n";
}
#print Dumper($perceptron), "\n";

# write ack to original file
my $ori_file_size = -s VALIDATION_DATA;
stdout_like {
    ok ( $perceptron->take_lab_test( {
                stimuli_validate => VALIDATION_DATA,
                predicted_column_index => 4,
            } ), 
            "Validate succedded!" );
} qr/book_list_validate\.csv/, "Correct output for take_lab_test when saving file";

t/06-validate_synonyms_mock.t  view on Meta::CPAN

my $perceptron = AI::Perceptron::Simple->new( {
    initial_value => 0.01,
    learning_rate => 0.001,
    threshold => 0.8,
    attribs => \@attributes
} );

my $nerve_file = $FindBin::Bin . "/perceptron_1.nerve";

for ( 0..5 ) {
    print "Round $_\n";
    $perceptron->train( TRAINING_DATA, "brand", $nerve_file, WANT_STATS, IDENTIFIER );
    print "\n";
}
#print Dumper($perceptron), "\n";

# write ack to original file
my $ori_file_size = -s VALIDATION_DATA;
stdout_like {
    ok ( $perceptron->take_mock_exam( {
                stimuli_validate => VALIDATION_DATA,
                predicted_column_index => 4,
            } ), 
            "Validate succedded!" );
} qr/book_list_validate\.csv/, "Correct output for take_mock_exam when saving file";



( run in 0.328 second using v1.01-cache-2.11-cpan-de7293f3b23 )