3
\$\begingroup\$

I've implemented the multiclass perceptron in the one vs. all style.

I just thought about it and tried to implement it in the most basic way. I think it's correct though my f_measure is a bit low. Which I believe is due in part to the fact that I haven't cleaned up my input, it's a feature vector of document words and I left all kinds of pronouns, 'the' and the like, which doubtless contribute not insignificantly to this confusion. In addition to the highly naieve tokenization of just every " ", quite rudimentary. ANYWAY, that's neither here nor there.

I'd like to know if some one among you might be able to devise a way to loopify this program, i.e. expunge this highly repetitive code and replace it with elegant loops.

public class MulticlassPerceptron 
{
      static int MAX_ITER = 100;
      static double LEARNING_RATE = 0.1;           
      static int theta = 0; 

      static final String LABEL_atheism = "atheism";
      static final String LABEL_sports = "sports";
      static final String LABEL_science = "science";
      static final String LABEL_politics = "politics";

      public static void perceptron( Table< int[] , String , Integer > train_freq_count_against_globo_dict,
                                     Table< int[] , String , Integer > test_freq_count_against_globo_dict,
                                     Set<String> GLOBO_DICT )
      {
          int globo_dict_size = GLOBO_DICT.size();
          int number_of_files__train = train_freq_count_against_globo_dict.size();

          double[] weights__science = new double[ globo_dict_size + 1 ];//one for bias
          double[] weights__sports = new double[ globo_dict_size + 1 ];//one for bias
          double[] weights__politics = new double[ globo_dict_size + 1 ];//one for bias
          double[] weights__atheism = new double[ globo_dict_size + 1 ];//one for bias

          for (int i = 0; i < ( globo_dict_size + 1 ); i++) 
          {
            weights__science[i] = randomNumber(0,1);
            weights__sports[i] = randomNumber(0,1);
            weights__politics[i] = randomNumber(0,1);
            weights__atheism[i] = randomNumber(0,1);
          }     

           double[][] feature_matrix__train = new double[ number_of_files__train ][ globo_dict_size ];
           int[] outputs__science = new int [ number_of_files__train ];
           int[] outputs__sports = new int [ number_of_files__train ];
           int[] outputs__politics = new int [ number_of_files__train ];
           int[] outputs__atheism = new int [ number_of_files__train ];

           int z = 0;
           for ( Cell< int[] , String , Integer > cell: train_freq_count_against_globo_dict.cellSet() )
           {               
               int[] container_of_feature_vector = cell.getRowKey();

               for (int q = 0; q < globo_dict_size; q++) 
               {
                   feature_matrix__train[z][q] = container_of_feature_vector[q];
               }
               outputs__science[z] =  String.valueOf( cell.getColumnKey() ).equals(LABEL_atheism)  ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_sports)   ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_politics) ? 0 : 1;

               outputs__sports[z] =   String.valueOf( cell.getColumnKey() ).equals(LABEL_atheism)  ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_science)  ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_politics) ? 0 : 1;

               outputs__politics[z] = String.valueOf( cell.getColumnKey() ).equals(LABEL_atheism)  ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_sports)   ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_science)  ? 0 : 1;

               outputs__atheism[z] =  String.valueOf( cell.getColumnKey() ).equals(LABEL_science)  ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_sports)   ||
                                      String.valueOf( cell.getColumnKey() ).equals(LABEL_politics) ? 0 : 1;
               z++;
           }

          //LEARNING WEIGHTS
          double localError, globalError;
          int p, iteration, output;

          //SCIENCE
          iteration = 0;
          do 
          {
              iteration++;
              globalError = 0;
              //loop through all instances (complete one epoch)
              for (p = 0; p < number_of_files__train; p++) 
              {
                  // calculate predicted class
                  output = calculateOutput( theta, weights__science, feature_matrix__train, p, globo_dict_size );
                  // difference between predicted and actual class values
                  localError = outputs__science[p] - output;
                  //update weights and bias
                  for (int i = 0; i < globo_dict_size; i++) 
                  {
                      weights__science[i] += ( LEARNING_RATE * localError * feature_matrix__train[p][i] );
                  }
                  weights__science[ globo_dict_size ] += ( LEARNING_RATE * localError );

                  //summation of squared error (error value for all instances)
                  globalError += (localError*localError);
              }

              /* Root Mean Squared Error */
              System.out.println("Science vs. All");
              if (iteration < 10) 
                  System.out.println("Iteration 0" + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
              else
                  System.out.println("Iteration " + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
          } 
          while(globalError != 0 && iteration<=MAX_ITER);


          //SPORTS
          iteration = 0;
          do 
          {
              iteration++;
              globalError = 0;
              //loop through all instances (complete one epoch)
              for (p = 0; p < number_of_files__train; p++) 
              {
                  // calculate predicted class
                  output = calculateOutput( theta, weights__sports, feature_matrix__train, p, globo_dict_size );
                  // difference between predicted and actual class values
                  localError = outputs__sports[p] - output;
                  //update weights and bias
                  for (int i = 0; i < globo_dict_size; i++) 
                  {
                      weights__sports[i] += ( LEARNING_RATE * localError * feature_matrix__train[p][i] );
                  }
                  weights__sports[ globo_dict_size ] += ( LEARNING_RATE * localError );

                  //summation of squared error (error value for all instances)
                  globalError += (localError*localError);
              }

              /* Root Mean Squared Error */
              System.out.println("Sports vs. All");
              if (iteration < 10) 
                  System.out.println("Iteration 0" + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
              else
                  System.out.println("Iteration " + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
          } 
          while(globalError != 0 && iteration<=MAX_ITER);


          //POLITICS
          iteration = 0;
          do 
          {
              iteration++;
              globalError = 0;
              //loop through all instances (complete one epoch)
              for (p = 0; p < number_of_files__train; p++) 
              {
                  // calculate predicted class
                  output = calculateOutput( theta, weights__politics, feature_matrix__train, p, globo_dict_size );
                  // difference between predicted and actual class values
                  localError = outputs__politics[p] - output;
                  //update weights and bias
                  for (int i = 0; i < globo_dict_size; i++) 
                  {
                      weights__politics[i] += ( LEARNING_RATE * localError * feature_matrix__train[p][i] );
                  }
                  weights__politics[ globo_dict_size ] += ( LEARNING_RATE * localError );

                  //summation of squared error (error value for all instances)
                  globalError += (localError*localError);
              }

              /* Root Mean Squared Error */
              System.out.println("Politics vs. All");
              if (iteration < 10) 
                  System.out.println("Iteration 0" + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
              else
                  System.out.println("Iteration " + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
          } 
          while(globalError != 0 && iteration<=MAX_ITER);


          //ATHEISM
          iteration = 0;
          do 
          {
              iteration++;
              globalError = 0;
              //loop through all instances (complete one epoch)
              for (p = 0; p < number_of_files__train; p++) 
              {
                  // calculate predicted class
                  output = calculateOutput( theta, weights__atheism, feature_matrix__train, p, globo_dict_size );
                  // difference between predicted and actual class values
                  localError = outputs__atheism[p] - output;
                  //update weights and bias
                  for (int i = 0; i < globo_dict_size; i++) 
                  {
                      weights__atheism[i] += ( LEARNING_RATE * localError * feature_matrix__train[p][i] );
                  }
                  weights__atheism[ globo_dict_size ] += ( LEARNING_RATE * localError );

                  //summation of squared error (error value for all instances)
                  globalError += (localError*localError);
              }

              /* Root Mean Squared Error */
              System.out.println("Atheism vs. All");
              if (iteration < 10) 
                  System.out.println("Iteration 0" + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
              else
                  System.out.println("Iteration " + iteration + " : RMSE = " + Math.sqrt( globalError/number_of_files__train ) );
          } 
          while(globalError != 0 && iteration<=MAX_ITER);






          //TEST   
           int number_of_files__test = test_freq_count_against_globo_dict.size();
           double[][] feature_matrix__test = new double[ number_of_files__test ][ globo_dict_size ];

           String[] test_file_true_label = new String [ number_of_files__test ];

           int x = 0;
           for ( Cell< int[] , String , Integer > cell: test_freq_count_against_globo_dict.cellSet() )
           {               
               int[] container_of_feature_vector__test = cell.getRowKey();

               for (int q = 0; q < globo_dict_size; q++) 
               {
                   feature_matrix__test[x][q] = container_of_feature_vector__test[q];
               }
               test_file_true_label[x] = (String)( cell.getColumnKey() );

               x++;
           }
           System.out.println();


           double tp_science = 0.0;
           double fp_science = 0.0; 
           double tn_science = 0.0;
           double fn_science = 0.0;

           double precision_science = 0.0;
           double recall_science = 0.0;
           double f_measure_science = 0.0;

           double tp_sports = 0.0;
           double fp_sports = 0.0; 
           double tn_sports = 0.0;
           double fn_sports = 0.0;

           double precision_sports = 0.0;
           double recall_sports = 0.0;
           double f_measure_sports = 0.0;

           double tp_atheism = 0.0;
           double fp_atheism = 0.0; 
           double tn_atheism = 0.0;
           double fn_atheism = 0.0;

           double precision_atheism = 0.0;
           double recall_atheism = 0.0;
           double f_measure_atheism = 0.0;

           double tp_politics = 0.0;
           double fp_politics = 0.0; 
           double tn_politics = 0.0;
           double fn_politics = 0.0;

           double precision_politics = 0.0;
           double recall_politics = 0.0;
           double f_measure_politics = 0.0;


           int actual_class = 0;

          for (p = 0; p < number_of_files__test; p++) 
          {

              int predict_science = calculateOutput( theta, weights__science, feature_matrix__test, p, globo_dict_size );

              actual_class = ( test_file_true_label[p] ).equals( LABEL_science ) ? 1 : 0;

              if( actual_class == 1 && predict_science == 1 )
                  tp_science++;
              if( actual_class == 1 && predict_science == 0 )
                  fn_science++;
              if( actual_class == 0 && predict_science == 1 )
                  fp_science++;
              if( actual_class == 0 && predict_science == 0 )
                  tn_science++;  

              int predict_sports = calculateOutput( theta, weights__sports, feature_matrix__test, p, globo_dict_size );

              actual_class = ( test_file_true_label[p] ).equals( LABEL_sports ) ? 1 : 0;

              if( actual_class == 1 && predict_sports == 1 )
                  tp_sports++;
              if( actual_class == 1 && predict_sports == 0 )
                  fn_sports++;
              if( actual_class == 0 && predict_sports == 1 )
                  fp_sports++;
              if( actual_class == 0 && predict_sports == 0 )
                  tn_sports++;

              int predict_politics = calculateOutput( theta, weights__politics, feature_matrix__test, p, globo_dict_size );

              actual_class = ( test_file_true_label[p] ).equals( LABEL_politics ) ? 1 : 0;

              if( actual_class == 1 && predict_politics == 1 )
                  tp_politics++;
              if( actual_class == 1 && predict_politics == 0 )
                  fn_politics++;
              if( actual_class == 0 && predict_politics == 1 )
                  fp_politics++;
              if( actual_class == 0 && predict_politics == 0 )
                  tn_politics++;

              int predict_atheism = calculateOutput( theta, weights__atheism, feature_matrix__test, p, globo_dict_size );

              actual_class = ( test_file_true_label[p] ).equals( LABEL_atheism ) ? 1 : 0;

              if( actual_class == 1 && predict_atheism == 1 )
                  tp_atheism++;
              if( actual_class == 1 && predict_atheism == 0 )
                  fn_atheism++;
              if( actual_class == 0 && predict_atheism == 1 )
                  fp_atheism++;
              if( actual_class == 0 && predict_atheism == 0 )
                  tn_atheism++; 

          }

          System.out.println( "SCIENCE");
          System.out.println( "tp_science: " + tp_science );
          System.out.println( "fp_science: " + fp_science );
          System.out.println( "tn_science: " + tn_science );
          System.out.println( "fn_science: " + fn_science );
          System.out.println();

          precision_science = tp_science / (tp_science + fp_science);
          System.out.println( "precision_science = " + precision_science );

          recall_science = tp_science / (tp_science + fn_science);
          System.out.println( "recall_science = " + recall_science );

          f_measure_science = ( 2 * ( precision_science * recall_science ) ) / ( precision_science + recall_science );
          System.out.println( "f_measure_science = " + f_measure_science );
          System.out.println();
          System.out.println();
          System.out.println();




          System.out.println( "SPORTS");
          System.out.println( "tp_sports: " + tp_sports );
          System.out.println( "fp_sports: " + fp_sports );
          System.out.println( "tn_sports: " + tn_sports );
          System.out.println( "fn_sports: " + fn_sports );
          System.out.println();

          precision_sports = tp_sports / (tp_sports + fp_sports);
          System.out.println( "precision_sports = " + precision_sports );

          recall_sports = tp_sports / (tp_sports + fn_sports);
          System.out.println( "recall_sports = " + recall_sports );

          f_measure_sports = ( 2 * ( precision_sports * recall_sports ) ) / ( precision_sports + recall_sports );
          System.out.println( "f_measure_sports = " + f_measure_sports );
          System.out.println();
          System.out.println();
          System.out.println();



          System.out.println( "POLITICS");
          System.out.println( "tp_politics: " + tp_politics );
          System.out.println( "fp_politics: " + fp_politics );
          System.out.println( "tn_politics: " + tn_politics );
          System.out.println( "fn_politics: " + fn_politics );
          System.out.println();

          precision_politics = tp_politics / (tp_politics + fp_politics);
          System.out.println( "precision_politics = " + precision_politics );

          recall_politics = tp_politics / (tp_politics + fn_politics);
          System.out.println( "recall_politics = " + recall_politics );

          f_measure_politics = ( 2 * ( precision_politics * recall_politics ) ) / ( precision_politics + recall_politics );
          System.out.println( "f_measure_politics = " + f_measure_politics );
          System.out.println();
          System.out.println();
          System.out.println();



          System.out.println( "ATHEISM");
          System.out.println( "tp_atheism: " + tp_atheism );
          System.out.println( "fp_atheism: " + fp_atheism );
          System.out.println( "tn_atheism" + tn_atheism );
          System.out.println( "fn_atheism: " + fn_atheism );
          System.out.println();

          precision_atheism = tp_atheism / (tp_atheism + fp_atheism);
          System.out.println( "precision_atheism = " + precision_atheism );

          recall_atheism = tp_atheism / (tp_atheism + fn_atheism);
          System.out.println( "recall_atheism = " + recall_atheism );

          f_measure_atheism = ( 2 * ( precision_atheism * recall_atheism ) ) / ( precision_atheism + recall_atheism );
          System.out.println( "f_measure_atheism = " + f_measure_atheism );
          System.out.println();
          System.out.println();
          System.out.println();



          System.out.println("------------------------------------------------------------------------");
          System.out.println();


          //average them!
          System.out.println( "AGREGATE");
          double precision = ( ( precision_atheism + precision_sports + precision_science + precision_politics ) / 4 );
          System.out.println( "precision = " + precision );

          double recall =  ( ( recall_atheism + recall_sports + recall_science + recall_politics ) / 4 );
          System.out.println( "recall = " + recall );

          double f_measure =  ( ( f_measure_atheism + f_measure_sports + f_measure_science + f_measure_politics ) / 4 );
          System.out.println( "f_measure = " + f_measure );



      }

The full code is here, on my github page.

\$\endgroup\$
  • \$\begingroup\$ Please don't ask people to write your code for you. Code Review is to get feedback and advice to improve the quality of your code and to help find and fix troubling bugs. codereview.stackexchange.com/help/on-topic \$\endgroup\$ – Fuzzy Logic Feb 28 '15 at 17:50
3
\$\begingroup\$

So, a few things.

  • The main advantage given by an Object-Oriented language is support for Objects. You should try some!
  • Your naming conventions are wildly against the java standards. Use camelCase, not snake_case. The use of double underscores is particularly noxious.
  • Variables should be private wherever possible, and final wherever possible.
  • Your spacing around generics and commas is wonky. They should look like this: for (Cell<int[], String, Integer> cell :
  • Likewise, parens don't have whitespace around them, except for a leading space after a control flow statement. if (foo) is correct, = ( foo * bar ) is not.
  • Most of your variable names are not at all descriptive. What's a 'globo'?

I took a start at an object that should remove a lot of duplication from your code. You'll need to make modifications to your existing classes in order to use it correctly. Hopefully it will put you on the right track. You will need to confirm the logic, as I probably made at least one mistake. It is final because it should not be extended. It is package scope (not public) because I do not expect it will need to be used outside its package. Obviously you will want to rename it.

final class Foo {

    private static final int BIAS = 1;

    private final String name;
    private final int dictSize;
    private final double[] weights;
    private final int[] outputs;

    public Foo(
            final String name,
            final int dictSize,
            final int numOutputs,
            final Table<int[], String, Integer> trainingTable) {

        this.name = name;

        this.dictSize = dictSize;

        this.weights = new double[dictSize + BIAS];
        for (int i = 0; i < this.weights.length; i++) {
            this.weights[i] = randomNumber(0, 1);
        }

        this.outputs = new int[numOutputs];
        this.initializeOutputs(trainingTable);
    }

    public void train(
            final int theta,
            final double learningRate,
            final double[][] trainingMatrix,
            final int maxIterations) {

        int iteration = 0;
        double globalError;
        do {
            iteration++;
            globalError = 0;

            //loop through all instances (complete one epoch)
            for (int p = 0; p < this.outputs.length; p++) {

                // calculate predicted class
                final int output =
                        this.calculateOutput(theta, trainingMatrix, p);

                // difference between predicted and actual class values
                final double localError = this.outputs[p] - output;

                //update weights and bias
                for (int i = 0; i < this.dictSize; i++) {
                    this.weights[i] += (learningRate * localError * trainingMatrix[p][i]);
                }
                this.weights[this.dictSize] += (learningRate * localError);

                //summation of squared error (error value for all instances)
                globalError += (localError * localError);
            }

            /* Root Mean Squared Error */
            System.out.println(this.name + " vs. All");
            System.out.println(
                    String.format("Iteration $d2 : RMSE = $f",
                            iteration, rootMeanSquaredError(globalError, trainingMatrix.length)));
        } while (globalError != 0 && iteration <= maxIterations);
    }

    private void initializeOutputs(final Table<int[], String, Integer> trainingTable) {
        int z = 0;

        for (final Cell<int[], String, Integer> cell: trainingTable.cellSet()) {
            final int[] container_of_feature_vector = cell.getRowKey();

            final String columnKey = String.valueOf(cell.getColumnKey());
            this.outputs[z] = columnKey.equalsIgnoreCase(this.name) ? 0 : 1;

            z++;
        }
    }

    private static final double rootMeanSquaredError(
            final double error,
            final double trainingSize) {
        return Math.sqrt(error / trainingSize);
    }

    public int calculateOutput(
            final int theta,
            final double[][] trainingMatrix,
            final int p) {
        throw new UnsupportedOperationException();
    }

    private static double randomNumber(final int minValue, final int maxValue) {
        throw new UnsupportedOperationException();
    }
}
\$\endgroup\$
2
\$\begingroup\$

These variables names that differ only one letter from each other:

double tp_science = 0.0;
double fp_science = 0.0; 
double tn_science = 0.0;
double fn_science = 0.0;

Please use more clearly distinguishable names.


expression ? 0 : 1

Means: if expression then 0 else 1, use ! (negation) instead

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.