/* * Perceptron.java * * Created on 28 May 2007, 19:26 * */ package comp316.assignment6; import java.util.ArrayList; import java.util.Random; import java.util.Arrays; /** * Perceptron Learning Algorithm * @author Nick Jenkin */ public class PerceptronLearning implements MLModel { // the learning rate of the perceptron private final double learningRate_ = 1; // an array of weights used for classification private double[] weights_; // the data set private ArrayList biasData_; public PerceptronLearning() { biasData_ = new ArrayList(); } // add an example public void addData(DataRow row) { biasData_.add(new BiasDataRow(row)); } // add lots of examples public void addData(ArrayList rows) { for(DataRow row : rows) { biasData_.add(new BiasDataRow(row)); } } /** * Calculate the weights for the perceptron learning */ public void commit() { Random rand = new Random(); double[] weights = new double[biasData_.get(0).numberOfAttributes()]; // initialize weights with random values for(int i=0; i < weights.length; i++) { weights[i] = rand.nextInt(20); } // monitors for changes in weights boolean weightChange = true; while(weightChange) { weightChange = false; for(BiasDataRow row : biasData_) { // calculate the input to be used on the activation function double input = 0; for(int j=0; j < row.numberOfAttributes(); j++) { input += weights[j] * row.getAttribute(j); } // if the err isn't 0, it means the weights have changed. double err = row.getTarget() - activationFunction(input); if(err != 0) { weightChange = true; // go through all the attributes and recalculate weights // the bias weight is j=0 which the BiasDataRow wraps in for(int j=0; j < row.numberOfAttributes(); j++) { weights[j] = weights[j] + learningRate_ * err * row.getAttribute(j); } } } } weights_ = weights; } // converts a boolean to an int // 1 = true 0 = false public int boolToInt(boolean val) { if(val) { return 1; } else { return 0; } } // the activation function // returns 1 if v is greater than 0 // false otherwise public double activationFunction(double v) { if(v > 0) { return 1; } else { return 0; } } // classifies a test row based on the weights calculated at commit() public boolean classify(DataRow row) { BiasDataRow biasRow = new BiasDataRow(row); // calculate the input for the activation function double input = 0; for(int i=0; i < weights_.length; i++) { input += weights_[i] * biasRow.getAttribute(i); } // returns 1 if the classification is true, 0 otherwise double result = activationFunction(input); if(result == 1) { return true; } else { return false; } } // resets the data public void reset() { biasData_.clear(); } // This represents a DataRow which has an extra attribute (the Bias attribute) class BiasDataRow { // the DataRow this represents public DataRow row; // the bias, fixed value of -1 public final int bias = -1; public BiasDataRow(DataRow row) { this.row = row; } // returns the number of attributes of row+1 public int numberOfAttributes() { return row.getAttributes().length + 1; } // gets an attribute, if index is 0 the bias is returned // otherwise the data is obtained from the DataRow public int getAttribute(int index) { if(index == 0) { return bias; } else { return boolToInt(row.getAttribute(index-1)); } } // returns the target value of row public int getTarget() { return boolToInt(row.getTarget()); } } }