http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java index 4c05632..b380ae8 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/LearningRule.java @@ -28,95 +28,95 @@ import com.yahoo.labs.samoa.moa.core.StringUtils; * Rule with LearningNode (statistical data). * * @author Anh Thu Vu - * + * */ public abstract class LearningRule extends Rule { - /** + /** * */ - private static final long serialVersionUID = 1L; - - /* - * Constructor - */ - public LearningRule() { - super(); - } - - /* - * LearningNode - */ - public abstract RuleRegressionNode getLearningNode(); + private static final long serialVersionUID = 1L; - public abstract void setLearningNode(RuleRegressionNode learningNode); - - /* - * No. of instances seen - */ - public long getInstancesSeen() { - return this.getLearningNode().getInstancesSeen(); - } + /* + * Constructor + */ + public LearningRule() { + super(); + } - /* - * Error and change detection - */ - public double computeError(Instance instance) { - return this.getLearningNode().computeError(instance); - } + /* + * LearningNode + */ + public abstract RuleRegressionNode getLearningNode(); + public abstract void setLearningNode(RuleRegressionNode learningNode); - /* - * Prediction - */ - public double[] getPrediction(Instance instance, int mode) { - return this.getLearningNode().getPrediction(instance, mode); - } - - public double[] getPrediction(Instance instance) { - return this.getLearningNode().getPrediction(instance); - } - - public double getCurrentError() { - return this.getLearningNode().getCurrentError(); - } - - /* - * Anomaly detection - */ - public boolean isAnomaly(Instance instance, - double uniVariateAnomalyProbabilityThreshold, - double multiVariateAnomalyProbabilityThreshold, - int numberOfInstanceesForAnomaly) { - return this.getLearningNode().isAnomaly(instance, uniVariateAnomalyProbabilityThreshold, - multiVariateAnomalyProbabilityThreshold, - numberOfInstanceesForAnomaly); - } - - /* - * Update - */ - public void updateStatistics(Instance instance) { - this.getLearningNode().updateStatistics(instance); - } - - public String printRule() { - StringBuilder out = new StringBuilder(); - int indent = 1; - StringUtils.appendIndented(out, indent, "Rule Nr." + this.ruleNumberID + " Instances seen:" + this.getLearningNode().getInstancesSeen() + "\n"); // AC - for (RuleSplitNode node : nodeList) { - StringUtils.appendIndented(out, indent, node.getSplitTest().toString()); - StringUtils.appendIndented(out, indent, " "); - StringUtils.appendIndented(out, indent, node.toString()); - } - DoubleVector pred = new DoubleVector(this.getLearningNode().getSimplePrediction()); - StringUtils.appendIndented(out, 0, " --> y: " + pred.toString()); - StringUtils.appendNewline(out); - - if(getLearningNode().perceptron!=null){ - ((RuleActiveRegressionNode)this.getLearningNode()).perceptron.getModelDescription(out,0); - StringUtils.appendNewline(out); - } - return(out.toString()); - } + /* + * No. of instances seen + */ + public long getInstancesSeen() { + return this.getLearningNode().getInstancesSeen(); + } + + /* + * Error and change detection + */ + public double computeError(Instance instance) { + return this.getLearningNode().computeError(instance); + } + + /* + * Prediction + */ + public double[] getPrediction(Instance instance, int mode) { + return this.getLearningNode().getPrediction(instance, mode); + } + + public double[] getPrediction(Instance instance) { + return this.getLearningNode().getPrediction(instance); + } + + public double getCurrentError() { + return this.getLearningNode().getCurrentError(); + } + + /* + * Anomaly detection + */ + public boolean isAnomaly(Instance instance, + double uniVariateAnomalyProbabilityThreshold, + double multiVariateAnomalyProbabilityThreshold, + int numberOfInstanceesForAnomaly) { + return this.getLearningNode().isAnomaly(instance, uniVariateAnomalyProbabilityThreshold, + multiVariateAnomalyProbabilityThreshold, + numberOfInstanceesForAnomaly); + } + + /* + * Update + */ + public void updateStatistics(Instance instance) { + this.getLearningNode().updateStatistics(instance); + } + + public String printRule() { + StringBuilder out = new StringBuilder(); + int indent = 1; + StringUtils.appendIndented(out, indent, "Rule Nr." + this.ruleNumberID + " Instances seen:" + + this.getLearningNode().getInstancesSeen() + "\n"); // AC + for (RuleSplitNode node : nodeList) { + StringUtils.appendIndented(out, indent, node.getSplitTest().toString()); + StringUtils.appendIndented(out, indent, " "); + StringUtils.appendIndented(out, indent, node.toString()); + } + DoubleVector pred = new DoubleVector(this.getLearningNode().getSimplePrediction()); + StringUtils.appendIndented(out, 0, " --> y: " + pred.toString()); + StringUtils.appendNewline(out); + + if (getLearningNode().perceptron != null) { + ((RuleActiveRegressionNode) this.getLearningNode()).perceptron.getModelDescription(out, 0); + StringUtils.appendNewline(out); + } + return (out.toString()); + } }
http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java index df5b9f9..7679dc3 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/NonLearningRule.java @@ -24,28 +24,28 @@ package com.yahoo.labs.samoa.learners.classifiers.rules.common; * The most basic rule: inherit from Rule the ID and list of features. * * @author Anh Thu Vu - * + * */ /* * This branch (Non-learning rule) was created for an old implementation. - * Probably should remove None-Learning and Learning Rule classes, - * merge Rule with LearningRule. + * Probably should remove None-Learning and Learning Rule classes, merge Rule + * with LearningRule. */ public class NonLearningRule extends Rule { - /** + /** * */ - private static final long serialVersionUID = -1210907339230307784L; + private static final long serialVersionUID = -1210907339230307784L; - public NonLearningRule(ActiveRule rule) { - this.nodeList = rule.nodeList; - this.ruleNumberID = rule.ruleNumberID; - } + public NonLearningRule(ActiveRule rule) { + this.nodeList = rule.nodeList; + this.ruleNumberID = rule.ruleNumberID; + } - @Override - public void getDescription(StringBuilder sb, int indent) { - // do nothing - } + @Override + public void getDescription(StringBuilder sb, int indent) { + // do nothing + } } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java index 8281d45..f49d0d9 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/PassiveRule.java @@ -23,49 +23,49 @@ package com.yahoo.labs.samoa.learners.classifiers.rules.common; import java.util.LinkedList; /** - * PassiveRule is a LearningRule that update its LearningNode - * with the received new LearningNode. + * PassiveRule is a LearningRule that update its LearningNode with the received + * new LearningNode. * * @author Anh Thu Vu - * + * */ public class PassiveRule extends LearningRule { - /** + /** * */ - private static final long serialVersionUID = -5551571895910530275L; - - private RulePassiveRegressionNode learningNode; + private static final long serialVersionUID = -5551571895910530275L; - /* - * Constructor to turn an ActiveRule into a PassiveRule - */ - public PassiveRule(ActiveRule rule) { - this.nodeList = new LinkedList<>(); - for (RuleSplitNode node:rule.nodeList) { - this.nodeList.add(node.getACopy()); - } - - this.learningNode = new RulePassiveRegressionNode(rule.getLearningNode()); - this.ruleNumberID = rule.ruleNumberID; - } - - @Override - public RuleRegressionNode getLearningNode() { - return this.learningNode; - } + private RulePassiveRegressionNode learningNode; - @Override - public void setLearningNode(RuleRegressionNode learningNode) { - this.learningNode = (RulePassiveRegressionNode) learningNode; - } - - /* - * MOA GUI - */ - @Override - public void getDescription(StringBuilder sb, int indent) { - // TODO Auto-generated method stub - } + /* + * Constructor to turn an ActiveRule into a PassiveRule + */ + public PassiveRule(ActiveRule rule) { + this.nodeList = new LinkedList<>(); + for (RuleSplitNode node : rule.nodeList) { + this.nodeList.add(node.getACopy()); + } + + this.learningNode = new RulePassiveRegressionNode(rule.getLearningNode()); + this.ruleNumberID = rule.ruleNumberID; + } + + @Override + public RuleRegressionNode getLearningNode() { + return this.learningNode; + } + + @Override + public void setLearningNode(RuleRegressionNode learningNode) { + this.learningNode = (RulePassiveRegressionNode) learningNode; + } + + /* + * MOA GUI + */ + @Override + public void getDescription(StringBuilder sb, int indent) { + // TODO Auto-generated method stub + } } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java index 53583ed..463dcdf 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Perceptron.java @@ -33,455 +33,458 @@ import com.yahoo.labs.samoa.moa.core.DoubleVector; import com.yahoo.labs.samoa.moa.core.Measurement; /** - * Prediction scheme using Perceptron: - * Predictions are computed according to a linear function of the attributes. + * Prediction scheme using Perceptron: Predictions are computed according to a + * linear function of the attributes. * * @author Anh Thu Vu - * + * */ public class Perceptron extends AbstractClassifier implements Regressor { - private final double SD_THRESHOLD = 0.0000001; //THRESHOLD for normalizing attribute and target values - - private static final long serialVersionUID = 1L; - - // public FlagOption constantLearningRatioDecayOption = new FlagOption( - // "learningRatio_Decay_set_constant", 'd', - // "Learning Ratio Decay in Perceptron set to be constant. (The next parameter)."); - // - // public FloatOption learningRatioOption = new FloatOption( - // "learningRatio", 'l', - // "Constante Learning Ratio to use for training the Perceptrons in the leaves.", 0.01); - // - // public FloatOption learningRateDecayOption = new FloatOption( - // "learningRateDecay", 'm', - // " Learning Rate decay to use for training the Perceptron.", 0.001); - // - // public FloatOption fadingFactorOption = new FloatOption( - // "fadingFactor", 'e', - // "Fading factor for the Perceptron accumulated error", 0.99, 0, 1); - - protected boolean constantLearningRatioDecay; - protected double originalLearningRatio; - - private double nError; - protected double fadingFactor = 0.99; - private double learningRatio; - protected double learningRateDecay = 0.001; - - // The Perception weights - protected double[] weightAttribute; - - // Statistics used for error calculations - public DoubleVector perceptronattributeStatistics = new DoubleVector(); - public DoubleVector squaredperceptronattributeStatistics = new DoubleVector(); - - // The number of instances contributing to this model - protected int perceptronInstancesSeen; - protected int perceptronYSeen; - - protected double accumulatedError; - - // If the model (weights) should be reset or not - protected boolean initialisePerceptron; - - protected double perceptronsumY; - protected double squaredperceptronsumY; - - - public Perceptron() { - this.initialisePerceptron = true; - } - - /* - * Perceptron - */ - public Perceptron(Perceptron p) { - this(p,false); - } - - public Perceptron(Perceptron p, boolean copyAccumulatedError) { - super(); - // this.constantLearningRatioDecayOption = p.constantLearningRatioDecayOption; - // this.learningRatioOption = p.learningRatioOption; - // this.learningRateDecayOption=p.learningRateDecayOption; - // this.fadingFactorOption = p.fadingFactorOption; - this.constantLearningRatioDecay = p.constantLearningRatioDecay; - this.originalLearningRatio = p.originalLearningRatio; - if (copyAccumulatedError) - this.accumulatedError = p.accumulatedError; - this.nError = p.nError; - this.fadingFactor = p.fadingFactor; - this.learningRatio = p.learningRatio; - this.learningRateDecay = p.learningRateDecay; - if (p.weightAttribute!=null) - this.weightAttribute = p.weightAttribute.clone(); - - this.perceptronattributeStatistics = new DoubleVector(p.perceptronattributeStatistics); - this.squaredperceptronattributeStatistics = new DoubleVector(p.squaredperceptronattributeStatistics); - this.perceptronInstancesSeen = p.perceptronInstancesSeen; - - this.initialisePerceptron = p.initialisePerceptron; - this.perceptronsumY = p.perceptronsumY; - this.squaredperceptronsumY = p.squaredperceptronsumY; - this.perceptronYSeen=p.perceptronYSeen; - } - - public Perceptron(PerceptronData p) { - super(); - this.constantLearningRatioDecay = p.constantLearningRatioDecay; - this.originalLearningRatio = p.originalLearningRatio; - this.nError = p.nError; - this.fadingFactor = p.fadingFactor; - this.learningRatio = p.learningRatio; - this.learningRateDecay = p.learningRateDecay; - if (p.weightAttribute!=null) - this.weightAttribute = p.weightAttribute.clone(); - - this.perceptronattributeStatistics = new DoubleVector(p.perceptronattributeStatistics); - this.squaredperceptronattributeStatistics = new DoubleVector(p.squaredperceptronattributeStatistics); - this.perceptronInstancesSeen = p.perceptronInstancesSeen; - - this.initialisePerceptron = p.initialisePerceptron; - this.perceptronsumY = p.perceptronsumY; - this.squaredperceptronsumY = p.squaredperceptronsumY; - this.perceptronYSeen=p.perceptronYSeen; - this.accumulatedError = p.accumulatedError; - } - - // private void printPerceptron() { - // System.out.println("Learning Ratio:"+this.learningRatio+" ("+this.originalLearningRatio+")"); - // System.out.println("Constant Learning Ratio Decay:"+this.constantLearningRatioDecay+" ("+this.learningRateDecay+")"); - // System.out.println("Error:"+this.accumulatedError+"/"+this.nError); - // System.out.println("Fading factor:"+this.fadingFactor); - // System.out.println("Perceptron Y:"+this.perceptronsumY+"/"+this.squaredperceptronsumY+"/"+this.perceptronYSeen); - // } - - /* - * Weights - */ - public void setWeights(double[] w) { - this.weightAttribute = w; - } - - public double[] getWeights() { - return this.weightAttribute; - } - - /* - * No. of instances seen - */ - public int getInstancesSeen() { - return perceptronInstancesSeen; - } - - public void setInstancesSeen(int pInstancesSeen) { - this.perceptronInstancesSeen = pInstancesSeen; - } - - /** - * A method to reset the model - */ - public void resetLearningImpl() { - this.initialisePerceptron = true; - this.reset(); - } - - public void reset(){ - this.nError=0.0; - this.accumulatedError = 0.0; - this.perceptronInstancesSeen = 0; - this.perceptronattributeStatistics = new DoubleVector(); - this.squaredperceptronattributeStatistics = new DoubleVector(); - this.perceptronsumY = 0.0; - this.squaredperceptronsumY = 0.0; - this.perceptronYSeen=0; - } - - public void resetError(){ - this.nError=0.0; - this.accumulatedError = 0.0; - } - - /** - * Update the model using the provided instance - */ - public void trainOnInstanceImpl(Instance inst) { - accumulatedError= Math.abs(this.prediction(inst)-inst.classValue()) + fadingFactor*accumulatedError; - nError=1+fadingFactor*nError; - // Initialise Perceptron if necessary - if (this.initialisePerceptron) { - //this.fadingFactor=this.fadingFactorOption.getValue(); - //this.classifierRandom.setSeed(randomSeedOption.getValue()); - this.classifierRandom.setSeed(randomSeed); - this.initialisePerceptron = false; // not in resetLearningImpl() because it needs Instance! - this.weightAttribute = new double[inst.numAttributes()]; - for (int j = 0; j < inst.numAttributes(); j++) { - weightAttribute[j] = 2 * this.classifierRandom.nextDouble() - 1; - } - // Update Learning Rate - learningRatio = originalLearningRatio; - //this.learningRateDecay = learningRateDecayOption.getValue(); - - } - - // Update attribute statistics - this.perceptronInstancesSeen++; - this.perceptronYSeen++; - - - for(int j = 0; j < inst.numAttributes() -1; j++) - { - perceptronattributeStatistics.addToValue(j, inst.value(j)); - squaredperceptronattributeStatistics.addToValue(j, inst.value(j)*inst.value(j)); - } - this.perceptronsumY += inst.classValue(); - this.squaredperceptronsumY += inst.classValue() * inst.classValue(); - - if(!constantLearningRatioDecay){ - learningRatio = originalLearningRatio / (1+ perceptronInstancesSeen*learningRateDecay); - } - - this.updateWeights(inst,learningRatio); - //this.printPerceptron(); - } - - /** - * Output the prediction made by this perceptron on the given instance - */ - private double prediction(Instance inst) - { - double[] normalizedInstance = normalizedInstance(inst); - double normalizedPrediction = prediction(normalizedInstance); - return denormalizedPrediction(normalizedPrediction); - } - - public double normalizedPrediction(Instance inst) - { - double[] normalizedInstance = normalizedInstance(inst); - return prediction(normalizedInstance); - } - - private double denormalizedPrediction(double normalizedPrediction) { - if (!this.initialisePerceptron){ - double meanY = perceptronsumY / perceptronYSeen; - double sdY = computeSD(squaredperceptronsumY, perceptronsumY, perceptronYSeen); - if (sdY > SD_THRESHOLD) - return normalizedPrediction * sdY + meanY; - else - return normalizedPrediction + meanY; - } - else - return normalizedPrediction; //Perceptron may have been "reseted". Use old weights to predict - - } - - public double prediction(double[] instanceValues) - { - double prediction = 0.0; - if(!this.initialisePerceptron) - { - for (int j = 0; j < instanceValues.length - 1; j++) { - prediction += this.weightAttribute[j] * instanceValues[j]; - } - prediction += this.weightAttribute[instanceValues.length - 1]; - } - return prediction; - } - - public double[] normalizedInstance(Instance inst){ - // Normalize Instance - double[] normalizedInstance = new double[inst.numAttributes()]; - for(int j = 0; j < inst.numAttributes() -1; j++) { - int instAttIndex = modelAttIndexToInstanceAttIndex(j); - double mean = perceptronattributeStatistics.getValue(j) / perceptronYSeen; - double sd = computeSD(squaredperceptronattributeStatistics.getValue(j), perceptronattributeStatistics.getValue(j), perceptronYSeen); - if (sd > SD_THRESHOLD) - normalizedInstance[j] = (inst.value(instAttIndex) - mean)/ sd; - else - normalizedInstance[j] = inst.value(instAttIndex) - mean; - } - return normalizedInstance; - } - - public double computeSD(double squaredVal, double val, int size) { - if (size > 1) { - return Math.sqrt((squaredVal - ((val * val) / size)) / (size - 1.0)); - } - return 0.0; - } - - public double updateWeights(Instance inst, double learningRatio ){ - // Normalize Instance - double[] normalizedInstance = normalizedInstance(inst); - // Compute the Normalized Prediction of Perceptron - double normalizedPredict= prediction(normalizedInstance); - double normalizedY = normalizeActualClassValue(inst); - double sumWeights = 0.0; - double delta = normalizedY - normalizedPredict; - - for (int j = 0; j < inst.numAttributes() - 1; j++) { - int instAttIndex = modelAttIndexToInstanceAttIndex(j); - if(inst.attribute(instAttIndex).isNumeric()) { - this.weightAttribute[j] += learningRatio * delta * normalizedInstance[j]; - sumWeights += Math.abs(this.weightAttribute[j]); - } - } - this.weightAttribute[inst.numAttributes() - 1] += learningRatio * delta; - sumWeights += Math.abs(this.weightAttribute[inst.numAttributes() - 1]); - if (sumWeights > inst.numAttributes()) { // Lasso regression - for (int j = 0; j < inst.numAttributes() - 1; j++) { - int instAttIndex = modelAttIndexToInstanceAttIndex(j); - if(inst.attribute(instAttIndex).isNumeric()) { - this.weightAttribute[j] = this.weightAttribute[j] / sumWeights; - } - } - this.weightAttribute[inst.numAttributes() - 1] = this.weightAttribute[inst.numAttributes() - 1] / sumWeights; - } - - return denormalizedPrediction(normalizedPredict); - } - - public void normalizeWeights(){ - double sumWeights = 0.0; - - for (double aWeightAttribute : this.weightAttribute) { - sumWeights += Math.abs(aWeightAttribute); - } - for (int j = 0; j < this.weightAttribute.length; j++) { - this.weightAttribute[j] = this.weightAttribute[j] / sumWeights; - } - } - - private double normalizeActualClassValue(Instance inst) { - double meanY = perceptronsumY / perceptronYSeen; - double sdY = computeSD(squaredperceptronsumY, perceptronsumY, perceptronYSeen); - - double normalizedY; - if (sdY > SD_THRESHOLD){ - normalizedY = (inst.classValue() - meanY) / sdY; - }else{ - normalizedY = inst.classValue() - meanY; - } - return normalizedY; - } - - @Override - public boolean isRandomizable() { - return true; - } - - @Override - public double[] getVotesForInstance(Instance inst) { - return new double[]{this.prediction(inst)}; - } - - @Override - protected Measurement[] getModelMeasurementsImpl() { - return null; - } - - @Override - public void getModelDescription(StringBuilder out, int indent) { - if(this.weightAttribute!=null){ - for(int i=0; i< this.weightAttribute.length-1; ++i) - { - if(this.weightAttribute[i]>=0 && i>0) - out.append(" +" + Math.round(this.weightAttribute[i]*1000)/1000.0 + " X" + i ); - else - out.append(" " + Math.round(this.weightAttribute[i]*1000)/1000.0 + " X" + i ); - } - if(this.weightAttribute[this.weightAttribute.length-1]>=0 ) - out.append(" +" + Math.round(this.weightAttribute[this.weightAttribute.length-1]*1000)/1000.0); - else - out.append(" " + Math.round(this.weightAttribute[this.weightAttribute.length-1]*1000)/1000.0); - } - } - - public void setLearningRatio(double learningRatio) { - this.learningRatio=learningRatio; - - } - - public double getCurrentError() - { - if (nError>0) - return accumulatedError/nError; - else - return Double.MAX_VALUE; - } - - public static class PerceptronData implements Serializable { - /** + private final double SD_THRESHOLD = 0.0000001; // THRESHOLD for normalizing + // attribute and target values + + private static final long serialVersionUID = 1L; + + // public FlagOption constantLearningRatioDecayOption = new FlagOption( + // "learningRatio_Decay_set_constant", 'd', + // "Learning Ratio Decay in Perceptron set to be constant. (The next parameter)."); + // + // public FloatOption learningRatioOption = new FloatOption( + // "learningRatio", 'l', + // "Constante Learning Ratio to use for training the Perceptrons in the leaves.", + // 0.01); + // + // public FloatOption learningRateDecayOption = new FloatOption( + // "learningRateDecay", 'm', + // " Learning Rate decay to use for training the Perceptron.", 0.001); + // + // public FloatOption fadingFactorOption = new FloatOption( + // "fadingFactor", 'e', + // "Fading factor for the Perceptron accumulated error", 0.99, 0, 1); + + protected boolean constantLearningRatioDecay; + protected double originalLearningRatio; + + private double nError; + protected double fadingFactor = 0.99; + private double learningRatio; + protected double learningRateDecay = 0.001; + + // The Perception weights + protected double[] weightAttribute; + + // Statistics used for error calculations + public DoubleVector perceptronattributeStatistics = new DoubleVector(); + public DoubleVector squaredperceptronattributeStatistics = new DoubleVector(); + + // The number of instances contributing to this model + protected int perceptronInstancesSeen; + protected int perceptronYSeen; + + protected double accumulatedError; + + // If the model (weights) should be reset or not + protected boolean initialisePerceptron; + + protected double perceptronsumY; + protected double squaredperceptronsumY; + + public Perceptron() { + this.initialisePerceptron = true; + } + + /* + * Perceptron + */ + public Perceptron(Perceptron p) { + this(p, false); + } + + public Perceptron(Perceptron p, boolean copyAccumulatedError) { + super(); + // this.constantLearningRatioDecayOption = + // p.constantLearningRatioDecayOption; + // this.learningRatioOption = p.learningRatioOption; + // this.learningRateDecayOption=p.learningRateDecayOption; + // this.fadingFactorOption = p.fadingFactorOption; + this.constantLearningRatioDecay = p.constantLearningRatioDecay; + this.originalLearningRatio = p.originalLearningRatio; + if (copyAccumulatedError) + this.accumulatedError = p.accumulatedError; + this.nError = p.nError; + this.fadingFactor = p.fadingFactor; + this.learningRatio = p.learningRatio; + this.learningRateDecay = p.learningRateDecay; + if (p.weightAttribute != null) + this.weightAttribute = p.weightAttribute.clone(); + + this.perceptronattributeStatistics = new DoubleVector(p.perceptronattributeStatistics); + this.squaredperceptronattributeStatistics = new DoubleVector(p.squaredperceptronattributeStatistics); + this.perceptronInstancesSeen = p.perceptronInstancesSeen; + + this.initialisePerceptron = p.initialisePerceptron; + this.perceptronsumY = p.perceptronsumY; + this.squaredperceptronsumY = p.squaredperceptronsumY; + this.perceptronYSeen = p.perceptronYSeen; + } + + public Perceptron(PerceptronData p) { + super(); + this.constantLearningRatioDecay = p.constantLearningRatioDecay; + this.originalLearningRatio = p.originalLearningRatio; + this.nError = p.nError; + this.fadingFactor = p.fadingFactor; + this.learningRatio = p.learningRatio; + this.learningRateDecay = p.learningRateDecay; + if (p.weightAttribute != null) + this.weightAttribute = p.weightAttribute.clone(); + + this.perceptronattributeStatistics = new DoubleVector(p.perceptronattributeStatistics); + this.squaredperceptronattributeStatistics = new DoubleVector(p.squaredperceptronattributeStatistics); + this.perceptronInstancesSeen = p.perceptronInstancesSeen; + + this.initialisePerceptron = p.initialisePerceptron; + this.perceptronsumY = p.perceptronsumY; + this.squaredperceptronsumY = p.squaredperceptronsumY; + this.perceptronYSeen = p.perceptronYSeen; + this.accumulatedError = p.accumulatedError; + } + + // private void printPerceptron() { + // System.out.println("Learning Ratio:"+this.learningRatio+" ("+this.originalLearningRatio+")"); + // System.out.println("Constant Learning Ratio Decay:"+this.constantLearningRatioDecay+" ("+this.learningRateDecay+")"); + // System.out.println("Error:"+this.accumulatedError+"/"+this.nError); + // System.out.println("Fading factor:"+this.fadingFactor); + // System.out.println("Perceptron Y:"+this.perceptronsumY+"/"+this.squaredperceptronsumY+"/"+this.perceptronYSeen); + // } + + /* + * Weights + */ + public void setWeights(double[] w) { + this.weightAttribute = w; + } + + public double[] getWeights() { + return this.weightAttribute; + } + + /* + * No. of instances seen + */ + public int getInstancesSeen() { + return perceptronInstancesSeen; + } + + public void setInstancesSeen(int pInstancesSeen) { + this.perceptronInstancesSeen = pInstancesSeen; + } + + /** + * A method to reset the model + */ + public void resetLearningImpl() { + this.initialisePerceptron = true; + this.reset(); + } + + public void reset() { + this.nError = 0.0; + this.accumulatedError = 0.0; + this.perceptronInstancesSeen = 0; + this.perceptronattributeStatistics = new DoubleVector(); + this.squaredperceptronattributeStatistics = new DoubleVector(); + this.perceptronsumY = 0.0; + this.squaredperceptronsumY = 0.0; + this.perceptronYSeen = 0; + } + + public void resetError() { + this.nError = 0.0; + this.accumulatedError = 0.0; + } + + /** + * Update the model using the provided instance + */ + public void trainOnInstanceImpl(Instance inst) { + accumulatedError = Math.abs(this.prediction(inst) - inst.classValue()) + fadingFactor * accumulatedError; + nError = 1 + fadingFactor * nError; + // Initialise Perceptron if necessary + if (this.initialisePerceptron) { + // this.fadingFactor=this.fadingFactorOption.getValue(); + // this.classifierRandom.setSeed(randomSeedOption.getValue()); + this.classifierRandom.setSeed(randomSeed); + this.initialisePerceptron = false; // not in resetLearningImpl() because + // it needs Instance! + this.weightAttribute = new double[inst.numAttributes()]; + for (int j = 0; j < inst.numAttributes(); j++) { + weightAttribute[j] = 2 * this.classifierRandom.nextDouble() - 1; + } + // Update Learning Rate + learningRatio = originalLearningRatio; + // this.learningRateDecay = learningRateDecayOption.getValue(); + + } + + // Update attribute statistics + this.perceptronInstancesSeen++; + this.perceptronYSeen++; + + for (int j = 0; j < inst.numAttributes() - 1; j++) + { + perceptronattributeStatistics.addToValue(j, inst.value(j)); + squaredperceptronattributeStatistics.addToValue(j, inst.value(j) * inst.value(j)); + } + this.perceptronsumY += inst.classValue(); + this.squaredperceptronsumY += inst.classValue() * inst.classValue(); + + if (!constantLearningRatioDecay) { + learningRatio = originalLearningRatio / (1 + perceptronInstancesSeen * learningRateDecay); + } + + this.updateWeights(inst, learningRatio); + // this.printPerceptron(); + } + + /** + * Output the prediction made by this perceptron on the given instance + */ + private double prediction(Instance inst) + { + double[] normalizedInstance = normalizedInstance(inst); + double normalizedPrediction = prediction(normalizedInstance); + return denormalizedPrediction(normalizedPrediction); + } + + public double normalizedPrediction(Instance inst) + { + double[] normalizedInstance = normalizedInstance(inst); + return prediction(normalizedInstance); + } + + private double denormalizedPrediction(double normalizedPrediction) { + if (!this.initialisePerceptron) { + double meanY = perceptronsumY / perceptronYSeen; + double sdY = computeSD(squaredperceptronsumY, perceptronsumY, perceptronYSeen); + if (sdY > SD_THRESHOLD) + return normalizedPrediction * sdY + meanY; + else + return normalizedPrediction + meanY; + } + else + return normalizedPrediction; // Perceptron may have been "reseted". Use + // old weights to predict + + } + + public double prediction(double[] instanceValues) + { + double prediction = 0.0; + if (!this.initialisePerceptron) + { + for (int j = 0; j < instanceValues.length - 1; j++) { + prediction += this.weightAttribute[j] * instanceValues[j]; + } + prediction += this.weightAttribute[instanceValues.length - 1]; + } + return prediction; + } + + public double[] normalizedInstance(Instance inst) { + // Normalize Instance + double[] normalizedInstance = new double[inst.numAttributes()]; + for (int j = 0; j < inst.numAttributes() - 1; j++) { + int instAttIndex = modelAttIndexToInstanceAttIndex(j); + double mean = perceptronattributeStatistics.getValue(j) / perceptronYSeen; + double sd = computeSD(squaredperceptronattributeStatistics.getValue(j), + perceptronattributeStatistics.getValue(j), perceptronYSeen); + if (sd > SD_THRESHOLD) + normalizedInstance[j] = (inst.value(instAttIndex) - mean) / sd; + else + normalizedInstance[j] = inst.value(instAttIndex) - mean; + } + return normalizedInstance; + } + + public double computeSD(double squaredVal, double val, int size) { + if (size > 1) { + return Math.sqrt((squaredVal - ((val * val) / size)) / (size - 1.0)); + } + return 0.0; + } + + public double updateWeights(Instance inst, double learningRatio) { + // Normalize Instance + double[] normalizedInstance = normalizedInstance(inst); + // Compute the Normalized Prediction of Perceptron + double normalizedPredict = prediction(normalizedInstance); + double normalizedY = normalizeActualClassValue(inst); + double sumWeights = 0.0; + double delta = normalizedY - normalizedPredict; + + for (int j = 0; j < inst.numAttributes() - 1; j++) { + int instAttIndex = modelAttIndexToInstanceAttIndex(j); + if (inst.attribute(instAttIndex).isNumeric()) { + this.weightAttribute[j] += learningRatio * delta * normalizedInstance[j]; + sumWeights += Math.abs(this.weightAttribute[j]); + } + } + this.weightAttribute[inst.numAttributes() - 1] += learningRatio * delta; + sumWeights += Math.abs(this.weightAttribute[inst.numAttributes() - 1]); + if (sumWeights > inst.numAttributes()) { // Lasso regression + for (int j = 0; j < inst.numAttributes() - 1; j++) { + int instAttIndex = modelAttIndexToInstanceAttIndex(j); + if (inst.attribute(instAttIndex).isNumeric()) { + this.weightAttribute[j] = this.weightAttribute[j] / sumWeights; + } + } + this.weightAttribute[inst.numAttributes() - 1] = this.weightAttribute[inst.numAttributes() - 1] / sumWeights; + } + + return denormalizedPrediction(normalizedPredict); + } + + public void normalizeWeights() { + double sumWeights = 0.0; + + for (double aWeightAttribute : this.weightAttribute) { + sumWeights += Math.abs(aWeightAttribute); + } + for (int j = 0; j < this.weightAttribute.length; j++) { + this.weightAttribute[j] = this.weightAttribute[j] / sumWeights; + } + } + + private double normalizeActualClassValue(Instance inst) { + double meanY = perceptronsumY / perceptronYSeen; + double sdY = computeSD(squaredperceptronsumY, perceptronsumY, perceptronYSeen); + + double normalizedY; + if (sdY > SD_THRESHOLD) { + normalizedY = (inst.classValue() - meanY) / sdY; + } else { + normalizedY = inst.classValue() - meanY; + } + return normalizedY; + } + + @Override + public boolean isRandomizable() { + return true; + } + + @Override + public double[] getVotesForInstance(Instance inst) { + return new double[] { this.prediction(inst) }; + } + + @Override + protected Measurement[] getModelMeasurementsImpl() { + return null; + } + + @Override + public void getModelDescription(StringBuilder out, int indent) { + if (this.weightAttribute != null) { + for (int i = 0; i < this.weightAttribute.length - 1; ++i) + { + if (this.weightAttribute[i] >= 0 && i > 0) + out.append(" +" + Math.round(this.weightAttribute[i] * 1000) / 1000.0 + " X" + i); + else + out.append(" " + Math.round(this.weightAttribute[i] * 1000) / 1000.0 + " X" + i); + } + if (this.weightAttribute[this.weightAttribute.length - 1] >= 0) + out.append(" +" + Math.round(this.weightAttribute[this.weightAttribute.length - 1] * 1000) / 1000.0); + else + out.append(" " + Math.round(this.weightAttribute[this.weightAttribute.length - 1] * 1000) / 1000.0); + } + } + + public void setLearningRatio(double learningRatio) { + this.learningRatio = learningRatio; + + } + + public double getCurrentError() + { + if (nError > 0) + return accumulatedError / nError; + else + return Double.MAX_VALUE; + } + + public static class PerceptronData implements Serializable { + /** * */ - private static final long serialVersionUID = 6727623208744105082L; - - private boolean constantLearningRatioDecay; - // If the model (weights) should be reset or not - private boolean initialisePerceptron; - - private double nError; - private double fadingFactor; - private double originalLearningRatio; - private double learningRatio; - private double learningRateDecay; - private double accumulatedError; - private double perceptronsumY; - private double squaredperceptronsumY; - - // The Perception weights - private double[] weightAttribute; - - // Statistics used for error calculations - private DoubleVector perceptronattributeStatistics; - private DoubleVector squaredperceptronattributeStatistics; - - // The number of instances contributing to this model - private int perceptronInstancesSeen; - private int perceptronYSeen; - - public PerceptronData() { - - } - - public PerceptronData(Perceptron p) { - this.constantLearningRatioDecay = p.constantLearningRatioDecay; - this.initialisePerceptron = p.initialisePerceptron; - this.nError = p.nError; - this.fadingFactor = p.fadingFactor; - this.originalLearningRatio = p.originalLearningRatio; - this.learningRatio = p.learningRatio; - this.learningRateDecay = p.learningRateDecay; - this.accumulatedError = p.accumulatedError; - this.perceptronsumY = p.perceptronsumY; - this.squaredperceptronsumY = p.squaredperceptronsumY; - this.weightAttribute = p.weightAttribute; - this.perceptronattributeStatistics = p.perceptronattributeStatistics; - this.squaredperceptronattributeStatistics = p.squaredperceptronattributeStatistics; - this.perceptronInstancesSeen = p.perceptronInstancesSeen; - this.perceptronYSeen = p.perceptronYSeen; - } - - public Perceptron build() { - return new Perceptron(this); - } - - } - - - public static final class PerceptronSerializer extends Serializer<Perceptron>{ - - @Override - public void write(Kryo kryo, Output output, Perceptron p) { - kryo.writeObjectOrNull(output, new PerceptronData(p), PerceptronData.class); - } - - @Override - public Perceptron read(Kryo kryo, Input input, Class<Perceptron> type) { - PerceptronData perceptronData = kryo.readObjectOrNull(input, PerceptronData.class); - return perceptronData.build(); - } - } + private static final long serialVersionUID = 6727623208744105082L; + + private boolean constantLearningRatioDecay; + // If the model (weights) should be reset or not + private boolean initialisePerceptron; + + private double nError; + private double fadingFactor; + private double originalLearningRatio; + private double learningRatio; + private double learningRateDecay; + private double accumulatedError; + private double perceptronsumY; + private double squaredperceptronsumY; + + // The Perception weights + private double[] weightAttribute; + + // Statistics used for error calculations + private DoubleVector perceptronattributeStatistics; + private DoubleVector squaredperceptronattributeStatistics; + + // The number of instances contributing to this model + private int perceptronInstancesSeen; + private int perceptronYSeen; + + public PerceptronData() { + + } + + public PerceptronData(Perceptron p) { + this.constantLearningRatioDecay = p.constantLearningRatioDecay; + this.initialisePerceptron = p.initialisePerceptron; + this.nError = p.nError; + this.fadingFactor = p.fadingFactor; + this.originalLearningRatio = p.originalLearningRatio; + this.learningRatio = p.learningRatio; + this.learningRateDecay = p.learningRateDecay; + this.accumulatedError = p.accumulatedError; + this.perceptronsumY = p.perceptronsumY; + this.squaredperceptronsumY = p.squaredperceptronsumY; + this.weightAttribute = p.weightAttribute; + this.perceptronattributeStatistics = p.perceptronattributeStatistics; + this.squaredperceptronattributeStatistics = p.squaredperceptronattributeStatistics; + this.perceptronInstancesSeen = p.perceptronInstancesSeen; + this.perceptronYSeen = p.perceptronYSeen; + } + + public Perceptron build() { + return new Perceptron(this); + } + + } + + public static final class PerceptronSerializer extends Serializer<Perceptron> { + + @Override + public void write(Kryo kryo, Output output, Perceptron p) { + kryo.writeObjectOrNull(output, new PerceptronData(p), PerceptronData.class); + } + + @Override + public Perceptron read(Kryo kryo, Input input, Class<Perceptron> type) { + PerceptronData perceptronData = kryo.readObjectOrNull(input, PerceptronData.class); + return perceptronData.build(); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java index b85cf10..0f58559 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/Rule.java @@ -28,84 +28,95 @@ import com.yahoo.labs.samoa.moa.AbstractMOAObject; import com.yahoo.labs.samoa.moa.classifiers.rules.core.conditionaltests.NumericAttributeBinaryRulePredicate; /** - * The base class for "rule". - * Represents the most basic rule with and ID and a list of features (nodeList). + * The base class for "rule". Represents the most basic rule with and ID and a + * list of features (nodeList). * * @author Anh Thu Vu - * + * */ public abstract class Rule extends AbstractMOAObject { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; + + protected int ruleNumberID; + + protected List<RuleSplitNode> nodeList; + + /* + * Constructor + */ + public Rule() { + this.nodeList = new LinkedList<RuleSplitNode>(); + } + + /* + * Rule ID + */ + public int getRuleNumberID() { + return ruleNumberID; + } + + public void setRuleNumberID(int ruleNumberID) { + this.ruleNumberID = ruleNumberID; + } + + /* + * RuleSplitNode list + */ + public List<RuleSplitNode> getNodeList() { + return nodeList; + } - protected int ruleNumberID; - - protected List<RuleSplitNode> nodeList; - - /* - * Constructor - */ - public Rule() { - this.nodeList = new LinkedList<RuleSplitNode>(); - } - - /* - * Rule ID - */ - public int getRuleNumberID() { - return ruleNumberID; - } + public void setNodeList(List<RuleSplitNode> nodeList) { + this.nodeList = nodeList; + } - public void setRuleNumberID(int ruleNumberID) { - this.ruleNumberID = ruleNumberID; - } - - /* - * RuleSplitNode list - */ - public List<RuleSplitNode> getNodeList() { - return nodeList; - } + /* + * Covering + */ + public boolean isCovering(Instance inst) { + boolean isCovering = true; + for (RuleSplitNode node : nodeList) { + if (node.evaluate(inst) == false) { + isCovering = false; + break; + } + } + return isCovering; + } - public void setNodeList(List<RuleSplitNode> nodeList) { - this.nodeList = nodeList; - } - - /* - * Covering - */ - public boolean isCovering(Instance inst) { - boolean isCovering = true; - for (RuleSplitNode node : nodeList) { - if (node.evaluate(inst) == false) { - isCovering = false; - break; - } - } - return isCovering; - } - - /* - * Add RuleSplitNode - */ - public boolean nodeListAdd(RuleSplitNode ruleSplitNode) { - //Check that the node is not already in the list - boolean isIncludedInNodeList = false; - boolean isUpdated=false; - for (RuleSplitNode node : nodeList) { - NumericAttributeBinaryRulePredicate nodeTest = (NumericAttributeBinaryRulePredicate) node.getSplitTest(); - NumericAttributeBinaryRulePredicate ruleSplitNodeTest = (NumericAttributeBinaryRulePredicate) ruleSplitNode.getSplitTest(); - if (nodeTest.isUsingSameAttribute(ruleSplitNodeTest)) { - isIncludedInNodeList = true; - if (nodeTest.isIncludedInRuleNode(ruleSplitNodeTest) == true) { //remove this line to keep the most recent attribute value - //replace the value - nodeTest.setAttributeValue(ruleSplitNodeTest); - isUpdated=true; //if is updated (i.e. an expansion happened) a new learning node should be created - } - } - } - if (isIncludedInNodeList == false) { - this.nodeList.add(ruleSplitNode); - } - return (!isIncludedInNodeList || isUpdated); - } + /* + * Add RuleSplitNode + */ + public boolean nodeListAdd(RuleSplitNode ruleSplitNode) { + // Check that the node is not already in the list + boolean isIncludedInNodeList = false; + boolean isUpdated = false; + for (RuleSplitNode node : nodeList) { + NumericAttributeBinaryRulePredicate nodeTest = (NumericAttributeBinaryRulePredicate) node.getSplitTest(); + NumericAttributeBinaryRulePredicate ruleSplitNodeTest = (NumericAttributeBinaryRulePredicate) ruleSplitNode + .getSplitTest(); + if (nodeTest.isUsingSameAttribute(ruleSplitNodeTest)) { + isIncludedInNodeList = true; + if (nodeTest.isIncludedInRuleNode(ruleSplitNodeTest) == true) { // remove + // this + // line + // to + // keep + // the + // most + // recent + // attribute + // value + // replace the value + nodeTest.setAttributeValue(ruleSplitNodeTest); + isUpdated = true; // if is updated (i.e. an expansion happened) a new + // learning node should be created + } + } + } + if (isIncludedInNodeList == false) { + this.nodeList.add(ruleSplitNode); + } + return (!isIncludedInNodeList || isUpdated); + } } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java index f52ac32..513340e 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveLearningNode.java @@ -21,14 +21,14 @@ package com.yahoo.labs.samoa.learners.classifiers.rules.common; */ /** - * Interface for Rule's LearningNode that updates both statistics - * for expanding rule and computing predictions. + * Interface for Rule's LearningNode that updates both statistics for expanding + * rule and computing predictions. * * @author Anh Thu Vu - * + * */ public interface RuleActiveLearningNode extends RulePassiveLearningNode { - public boolean tryToExpand(double splitConfidence, double tieThreshold); - + public boolean tryToExpand(double splitConfidence, double tieThreshold); + } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java index 05079ed..48daf7a 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RuleActiveRegressionNode.java @@ -37,282 +37,297 @@ import com.yahoo.labs.samoa.moa.classifiers.rules.driftdetection.PageHinkleyFadi import com.yahoo.labs.samoa.moa.classifiers.rules.driftdetection.PageHinkleyTest; /** - * LearningNode for regression rule that updates both statistics for - * expanding rule and computing predictions. + * LearningNode for regression rule that updates both statistics for expanding + * rule and computing predictions. * * @author Anh Thu Vu - * + * */ public class RuleActiveRegressionNode extends RuleRegressionNode implements RuleActiveLearningNode { - /** + /** * */ - private static final long serialVersionUID = 519854943188168546L; - - protected int splitIndex = 0; - - protected PageHinkleyTest pageHinckleyTest; - protected boolean changeDetection; - - protected double[] statisticsNewRuleActiveLearningNode = null; - protected double[] statisticsBranchSplit = null; - protected double[] statisticsOtherBranchSplit; - - protected AttributeSplitSuggestion bestSuggestion = null; - - protected AutoExpandVector<AttributeClassObserver> attributeObservers = new AutoExpandVector<>(); - private FIMTDDNumericAttributeClassLimitObserver numericObserver; - - /* - * Simple setters & getters - */ - public int getSplitIndex() { - return splitIndex; - } - - public void setSplitIndex(int splitIndex) { - this.splitIndex = splitIndex; - } - - public double[] getStatisticsOtherBranchSplit() { - return statisticsOtherBranchSplit; - } - - public void setStatisticsOtherBranchSplit(double[] statisticsOtherBranchSplit) { - this.statisticsOtherBranchSplit = statisticsOtherBranchSplit; - } - - public double[] getStatisticsBranchSplit() { - return statisticsBranchSplit; - } - - public void setStatisticsBranchSplit(double[] statisticsBranchSplit) { - this.statisticsBranchSplit = statisticsBranchSplit; - } - - public double[] getStatisticsNewRuleActiveLearningNode() { - return statisticsNewRuleActiveLearningNode; - } - - public void setStatisticsNewRuleActiveLearningNode( - double[] statisticsNewRuleActiveLearningNode) { - this.statisticsNewRuleActiveLearningNode = statisticsNewRuleActiveLearningNode; - } - - public AttributeSplitSuggestion getBestSuggestion() { - return bestSuggestion; - } - - public void setBestSuggestion(AttributeSplitSuggestion bestSuggestion) { - this.bestSuggestion = bestSuggestion; - } - - /* - * Constructor with builder - */ - public RuleActiveRegressionNode() { - super(); - } - public RuleActiveRegressionNode(ActiveRule.Builder builder) { - super(builder.statistics); - this.changeDetection = builder.changeDetection; - if (!builder.changeDetection) { - this.pageHinckleyTest = new PageHinkleyFading(builder.threshold, builder.alpha); + private static final long serialVersionUID = 519854943188168546L; + + protected int splitIndex = 0; + + protected PageHinkleyTest pageHinckleyTest; + protected boolean changeDetection; + + protected double[] statisticsNewRuleActiveLearningNode = null; + protected double[] statisticsBranchSplit = null; + protected double[] statisticsOtherBranchSplit; + + protected AttributeSplitSuggestion bestSuggestion = null; + + protected AutoExpandVector<AttributeClassObserver> attributeObservers = new AutoExpandVector<>(); + private FIMTDDNumericAttributeClassLimitObserver numericObserver; + + /* + * Simple setters & getters + */ + public int getSplitIndex() { + return splitIndex; + } + + public void setSplitIndex(int splitIndex) { + this.splitIndex = splitIndex; + } + + public double[] getStatisticsOtherBranchSplit() { + return statisticsOtherBranchSplit; + } + + public void setStatisticsOtherBranchSplit(double[] statisticsOtherBranchSplit) { + this.statisticsOtherBranchSplit = statisticsOtherBranchSplit; + } + + public double[] getStatisticsBranchSplit() { + return statisticsBranchSplit; + } + + public void setStatisticsBranchSplit(double[] statisticsBranchSplit) { + this.statisticsBranchSplit = statisticsBranchSplit; + } + + public double[] getStatisticsNewRuleActiveLearningNode() { + return statisticsNewRuleActiveLearningNode; + } + + public void setStatisticsNewRuleActiveLearningNode( + double[] statisticsNewRuleActiveLearningNode) { + this.statisticsNewRuleActiveLearningNode = statisticsNewRuleActiveLearningNode; + } + + public AttributeSplitSuggestion getBestSuggestion() { + return bestSuggestion; + } + + public void setBestSuggestion(AttributeSplitSuggestion bestSuggestion) { + this.bestSuggestion = bestSuggestion; + } + + /* + * Constructor with builder + */ + public RuleActiveRegressionNode() { + super(); + } + + public RuleActiveRegressionNode(ActiveRule.Builder builder) { + super(builder.statistics); + this.changeDetection = builder.changeDetection; + if (!builder.changeDetection) { + this.pageHinckleyTest = new PageHinkleyFading(builder.threshold, builder.alpha); + } + this.predictionFunction = builder.predictionFunction; + this.learningRatio = builder.learningRatio; + this.ruleNumberID = builder.id; + this.numericObserver = builder.numericObserver; + + this.perceptron = new Perceptron(); + this.perceptron.prepareForUse(); + this.perceptron.originalLearningRatio = builder.learningRatio; + this.perceptron.constantLearningRatioDecay = builder.constantLearningRatioDecay; + + if (this.predictionFunction != 1) + { + this.targetMean = new TargetMean(); + if (builder.statistics[0] > 0) + this.targetMean.reset(builder.statistics[1] / builder.statistics[0], (long) builder.statistics[0]); + } + this.predictionFunction = builder.predictionFunction; + if (builder.statistics != null) + this.nodeStatistics = new DoubleVector(builder.statistics); + } + + /* + * Update with input instance + */ + public boolean updatePageHinckleyTest(double error) { + boolean changeDetected = false; + if (!this.changeDetection) { + changeDetected = pageHinckleyTest.update(error); + } + return changeDetected; + } + + public boolean updateChangeDetection(double error) { + return !changeDetection && pageHinckleyTest.update(error); + } + + @Override + public void updateStatistics(Instance inst) { + // Update the statistics for this node + // number of instances passing through the node + nodeStatistics.addToValue(0, 1); + // sum of y values + nodeStatistics.addToValue(1, inst.classValue()); + // sum of squared y values + nodeStatistics.addToValue(2, inst.classValue() * inst.classValue()); + + for (int i = 0; i < inst.numAttributes() - 1; i++) { + int instAttIndex = modelAttIndexToInstanceAttIndex(i, inst); + + AttributeClassObserver obs = this.attributeObservers.get(i); + if (obs == null) { + // At this stage all nominal attributes are ignored + if (inst.attribute(instAttIndex).isNumeric()) // instAttIndex + { + obs = newNumericClassObserver(); + this.attributeObservers.set(i, obs); } - this.predictionFunction = builder.predictionFunction; - this.learningRatio = builder.learningRatio; - this.ruleNumberID = builder.id; - this.numericObserver = builder.numericObserver; - - this.perceptron = new Perceptron(); - this.perceptron.prepareForUse(); - this.perceptron.originalLearningRatio = builder.learningRatio; - this.perceptron.constantLearningRatioDecay = builder.constantLearningRatioDecay; - - - if(this.predictionFunction!=1) - { - this.targetMean = new TargetMean(); - if (builder.statistics[0]>0) - this.targetMean.reset(builder.statistics[1]/builder.statistics[0],(long)builder.statistics[0]); - } - this.predictionFunction = builder.predictionFunction; - if (builder.statistics!=null) - this.nodeStatistics=new DoubleVector(builder.statistics); - } - - /* - * Update with input instance - */ - public boolean updatePageHinckleyTest(double error) { - boolean changeDetected = false; - if (!this.changeDetection) { - changeDetected = pageHinckleyTest.update(error); - } - return changeDetected; - } - - public boolean updateChangeDetection(double error) { - return !changeDetection && pageHinckleyTest.update(error); - } - - @Override - public void updateStatistics(Instance inst) { - // Update the statistics for this node - // number of instances passing through the node - nodeStatistics.addToValue(0, 1); - // sum of y values - nodeStatistics.addToValue(1, inst.classValue()); - // sum of squared y values - nodeStatistics.addToValue(2, inst.classValue()*inst.classValue()); - - for (int i = 0; i < inst.numAttributes() - 1; i++) { - int instAttIndex = modelAttIndexToInstanceAttIndex(i, inst); - - AttributeClassObserver obs = this.attributeObservers.get(i); - if (obs == null) { - // At this stage all nominal attributes are ignored - if (inst.attribute(instAttIndex).isNumeric()) //instAttIndex - { - obs = newNumericClassObserver(); - this.attributeObservers.set(i, obs); - } - } - if (obs != null) { - ((FIMTDDNumericAttributeClassObserver) obs).observeAttributeClass(inst.value(instAttIndex), inst.classValue(), inst.weight()); - } - } - - this.perceptron.trainOnInstance(inst); - if (this.predictionFunction != 1) { //Train target mean if prediction function is not Perceptron - this.targetMean.trainOnInstance(inst); - } - } - - protected AttributeClassObserver newNumericClassObserver() { - //return new FIMTDDNumericAttributeClassObserver(); - //return new FIMTDDNumericAttributeClassLimitObserver(); - //return (AttributeClassObserver)((AttributeClassObserver)this.numericObserverOption.getPreMaterializedObject()).copy(); - FIMTDDNumericAttributeClassLimitObserver newObserver = new FIMTDDNumericAttributeClassLimitObserver(); - newObserver.setMaxNodes(numericObserver.getMaxNodes()); - return newObserver; + } + if (obs != null) { + ((FIMTDDNumericAttributeClassObserver) obs).observeAttributeClass(inst.value(instAttIndex), inst.classValue(), + inst.weight()); + } } - - /* - * Init after being split from oldLearningNode - */ - public void initialize(RuleRegressionNode oldLearningNode) { - if(oldLearningNode.perceptron!=null) - { - this.perceptron=new Perceptron(oldLearningNode.perceptron); - this.perceptron.resetError(); - this.perceptron.setLearningRatio(oldLearningNode.learningRatio); - } - - if(oldLearningNode.targetMean!=null) - { - this.targetMean= new TargetMean(oldLearningNode.targetMean); - this.targetMean.resetError(); - } - //reset statistics - this.nodeStatistics.setValue(0, 0); - this.nodeStatistics.setValue(1, 0); - this.nodeStatistics.setValue(2, 0); - } - - /* - * Expand - */ - @Override - public boolean tryToExpand(double splitConfidence, double tieThreshold) { - - // splitConfidence. Hoeffding Bound test parameter. - // tieThreshold. Hoeffding Bound test parameter. - SplitCriterion splitCriterion = new SDRSplitCriterionAMRules(); - //SplitCriterion splitCriterion = new SDRSplitCriterionAMRulesNode();//JD for assessing only best branch - - // Using this criterion, find the best split per attribute and rank the results - AttributeSplitSuggestion[] bestSplitSuggestions = this.getBestSplitSuggestions(splitCriterion); - Arrays.sort(bestSplitSuggestions); - // Declare a variable to determine if any of the splits should be performed - boolean shouldSplit = false; - - // If only one split was returned, use it - if (bestSplitSuggestions.length < 2) { - shouldSplit = ((bestSplitSuggestions.length > 0) && (bestSplitSuggestions[0].merit > 0)); - bestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 1]; - } // Otherwise, consider which of the splits proposed may be worth trying - else { - // Determine the hoeffding bound value, used to select how many instances should be used to make a test decision - // to feel reasonably confident that the test chosen by this sample is the same as what would be chosen using infinite examples - double hoeffdingBound = computeHoeffdingBound(1, splitConfidence, getInstancesSeen()); - // Determine the top two ranked splitting suggestions - bestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 1]; - AttributeSplitSuggestion secondBestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 2]; - - // If the upper bound of the sample mean for the ratio of SDR(best suggestion) to SDR(second best suggestion), - // as determined using the hoeffding bound, is less than 1, then the true mean is also less than 1, and thus at this - // particular moment of observation the bestSuggestion is indeed the best split option with confidence 1-delta, and - // splitting should occur. - // Alternatively, if two or more splits are very similar or identical in terms of their splits, then a threshold limit - // (default 0.05) is applied to the hoeffding bound; if the hoeffding bound is smaller than this limit then the two - // competing attributes are equally good, and the split will be made on the one with the higher SDR value. - - if (bestSuggestion.merit > 0) { - if ((((secondBestSuggestion.merit / bestSuggestion.merit) + hoeffdingBound) < 1) - || (hoeffdingBound < tieThreshold)) { - shouldSplit = true; - } - } - } - - if (shouldSplit) { - AttributeSplitSuggestion splitDecision = bestSplitSuggestions[bestSplitSuggestions.length - 1]; - double minValue = Double.MAX_VALUE; - double[] branchMerits = SDRSplitCriterionAMRules.computeBranchSplitMerits(bestSuggestion.resultingClassDistributions); - - for (int i = 0; i < bestSuggestion.numSplits(); i++) { - double value = branchMerits[i]; - if (value < minValue) { - minValue = value; - splitIndex = i; - statisticsNewRuleActiveLearningNode = bestSuggestion.resultingClassDistributionFromSplit(i); - } - } - statisticsBranchSplit = splitDecision.resultingClassDistributionFromSplit(splitIndex); - statisticsOtherBranchSplit = bestSuggestion.resultingClassDistributionFromSplit(splitIndex == 0 ? 1 : 0); - - } - return shouldSplit; - } - - public AutoExpandVector<AttributeClassObserver> getAttributeObservers() { - return this.attributeObservers; - } - - public AttributeSplitSuggestion[] getBestSplitSuggestions(SplitCriterion criterion) { - - List<AttributeSplitSuggestion> bestSuggestions = new LinkedList<AttributeSplitSuggestion>(); - - // Set the nodeStatistics up as the preSplitDistribution, rather than the observedClassDistribution - double[] nodeSplitDist = this.nodeStatistics.getArrayCopy(); - for (int i = 0; i < this.attributeObservers.size(); i++) { - AttributeClassObserver obs = this.attributeObservers.get(i); - if (obs != null) { - - // AT THIS STAGE NON-NUMERIC ATTRIBUTES ARE IGNORED - AttributeSplitSuggestion bestSuggestion = null; - if (obs instanceof FIMTDDNumericAttributeClassObserver) { - bestSuggestion = obs.getBestEvaluatedSplitSuggestion(criterion, nodeSplitDist, i, true); - } - - if (bestSuggestion != null) { - bestSuggestions.add(bestSuggestion); - } - } - } - return bestSuggestions.toArray(new AttributeSplitSuggestion[bestSuggestions.size()]); - } - + + this.perceptron.trainOnInstance(inst); + if (this.predictionFunction != 1) { // Train target mean if prediction + // function is not Perceptron + this.targetMean.trainOnInstance(inst); + } + } + + protected AttributeClassObserver newNumericClassObserver() { + // return new FIMTDDNumericAttributeClassObserver(); + // return new FIMTDDNumericAttributeClassLimitObserver(); + // return + // (AttributeClassObserver)((AttributeClassObserver)this.numericObserverOption.getPreMaterializedObject()).copy(); + FIMTDDNumericAttributeClassLimitObserver newObserver = new FIMTDDNumericAttributeClassLimitObserver(); + newObserver.setMaxNodes(numericObserver.getMaxNodes()); + return newObserver; + } + + /* + * Init after being split from oldLearningNode + */ + public void initialize(RuleRegressionNode oldLearningNode) { + if (oldLearningNode.perceptron != null) + { + this.perceptron = new Perceptron(oldLearningNode.perceptron); + this.perceptron.resetError(); + this.perceptron.setLearningRatio(oldLearningNode.learningRatio); + } + + if (oldLearningNode.targetMean != null) + { + this.targetMean = new TargetMean(oldLearningNode.targetMean); + this.targetMean.resetError(); + } + // reset statistics + this.nodeStatistics.setValue(0, 0); + this.nodeStatistics.setValue(1, 0); + this.nodeStatistics.setValue(2, 0); + } + + /* + * Expand + */ + @Override + public boolean tryToExpand(double splitConfidence, double tieThreshold) { + + // splitConfidence. Hoeffding Bound test parameter. + // tieThreshold. Hoeffding Bound test parameter. + SplitCriterion splitCriterion = new SDRSplitCriterionAMRules(); + // SplitCriterion splitCriterion = new SDRSplitCriterionAMRulesNode();//JD + // for assessing only best branch + + // Using this criterion, find the best split per attribute and rank the + // results + AttributeSplitSuggestion[] bestSplitSuggestions = this.getBestSplitSuggestions(splitCriterion); + Arrays.sort(bestSplitSuggestions); + // Declare a variable to determine if any of the splits should be performed + boolean shouldSplit = false; + + // If only one split was returned, use it + if (bestSplitSuggestions.length < 2) { + shouldSplit = ((bestSplitSuggestions.length > 0) && (bestSplitSuggestions[0].merit > 0)); + bestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 1]; + } // Otherwise, consider which of the splits proposed may be worth trying + else { + // Determine the hoeffding bound value, used to select how many instances + // should be used to make a test decision + // to feel reasonably confident that the test chosen by this sample is the + // same as what would be chosen using infinite examples + double hoeffdingBound = computeHoeffdingBound(1, splitConfidence, getInstancesSeen()); + // Determine the top two ranked splitting suggestions + bestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 1]; + AttributeSplitSuggestion secondBestSuggestion = bestSplitSuggestions[bestSplitSuggestions.length - 2]; + + // If the upper bound of the sample mean for the ratio of SDR(best + // suggestion) to SDR(second best suggestion), + // as determined using the hoeffding bound, is less than 1, then the true + // mean is also less than 1, and thus at this + // particular moment of observation the bestSuggestion is indeed the best + // split option with confidence 1-delta, and + // splitting should occur. + // Alternatively, if two or more splits are very similar or identical in + // terms of their splits, then a threshold limit + // (default 0.05) is applied to the hoeffding bound; if the hoeffding + // bound is smaller than this limit then the two + // competing attributes are equally good, and the split will be made on + // the one with the higher SDR value. + + if (bestSuggestion.merit > 0) { + if ((((secondBestSuggestion.merit / bestSuggestion.merit) + hoeffdingBound) < 1) + || (hoeffdingBound < tieThreshold)) { + shouldSplit = true; + } + } + } + + if (shouldSplit) { + AttributeSplitSuggestion splitDecision = bestSplitSuggestions[bestSplitSuggestions.length - 1]; + double minValue = Double.MAX_VALUE; + double[] branchMerits = SDRSplitCriterionAMRules + .computeBranchSplitMerits(bestSuggestion.resultingClassDistributions); + + for (int i = 0; i < bestSuggestion.numSplits(); i++) { + double value = branchMerits[i]; + if (value < minValue) { + minValue = value; + splitIndex = i; + statisticsNewRuleActiveLearningNode = bestSuggestion.resultingClassDistributionFromSplit(i); + } + } + statisticsBranchSplit = splitDecision.resultingClassDistributionFromSplit(splitIndex); + statisticsOtherBranchSplit = bestSuggestion.resultingClassDistributionFromSplit(splitIndex == 0 ? 1 : 0); + + } + return shouldSplit; + } + + public AutoExpandVector<AttributeClassObserver> getAttributeObservers() { + return this.attributeObservers; + } + + public AttributeSplitSuggestion[] getBestSplitSuggestions(SplitCriterion criterion) { + + List<AttributeSplitSuggestion> bestSuggestions = new LinkedList<AttributeSplitSuggestion>(); + + // Set the nodeStatistics up as the preSplitDistribution, rather than the + // observedClassDistribution + double[] nodeSplitDist = this.nodeStatistics.getArrayCopy(); + for (int i = 0; i < this.attributeObservers.size(); i++) { + AttributeClassObserver obs = this.attributeObservers.get(i); + if (obs != null) { + + // AT THIS STAGE NON-NUMERIC ATTRIBUTES ARE IGNORED + AttributeSplitSuggestion bestSuggestion = null; + if (obs instanceof FIMTDDNumericAttributeClassObserver) { + bestSuggestion = obs.getBestEvaluatedSplitSuggestion(criterion, nodeSplitDist, i, true); + } + + if (bestSuggestion != null) { + bestSuggestions.add(bestSuggestion); + } + } + } + return bestSuggestions.toArray(new AttributeSplitSuggestion[bestSuggestions.size()]); + } + } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java index 4934225..5bc47f5 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveLearningNode.java @@ -21,13 +21,12 @@ package com.yahoo.labs.samoa.learners.classifiers.rules.common; */ /** - * Interface for Rule's LearningNode that does not update - * statistics for expanding rule. It only updates statistics for - * computing predictions. + * Interface for Rule's LearningNode that does not update statistics for + * expanding rule. It only updates statistics for computing predictions. * * @author Anh Thu Vu - * + * */ -public interface RulePassiveLearningNode { +public interface RulePassiveLearningNode { } http://git-wip-us.apache.org/repos/asf/incubator-samoa/blob/23a35dbe/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java ---------------------------------------------------------------------- diff --git a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java index 674e482..086c9e1 100644 --- a/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java +++ b/samoa-api/src/main/java/com/yahoo/labs/samoa/learners/classifiers/rules/common/RulePassiveRegressionNode.java @@ -24,53 +24,53 @@ import com.yahoo.labs.samoa.instances.Instance; import com.yahoo.labs.samoa.moa.core.DoubleVector; /** - * LearningNode for regression rule that does not update - * statistics for expanding rule. It only updates statistics for - * computing predictions. + * LearningNode for regression rule that does not update statistics for + * expanding rule. It only updates statistics for computing predictions. * * @author Anh Thu Vu - * + * */ public class RulePassiveRegressionNode extends RuleRegressionNode implements RulePassiveLearningNode { - /** + /** * */ - private static final long serialVersionUID = 3720878438856489690L; - - public RulePassiveRegressionNode (double[] statistics) { - super(statistics); - } - - public RulePassiveRegressionNode() { - super(); - } - - public RulePassiveRegressionNode(RuleRegressionNode activeLearningNode) { - this.predictionFunction = activeLearningNode.predictionFunction; - this.ruleNumberID = activeLearningNode.ruleNumberID; - this.nodeStatistics = new DoubleVector(activeLearningNode.nodeStatistics); - this.learningRatio = activeLearningNode.learningRatio; - this.perceptron = new Perceptron(activeLearningNode.perceptron, true); - this.targetMean = new TargetMean(activeLearningNode.targetMean); - } - - /* - * Update with input instance - */ - @Override - public void updateStatistics(Instance inst) { - // Update the statistics for this node - // number of instances passing through the node - nodeStatistics.addToValue(0, 1); - // sum of y values - nodeStatistics.addToValue(1, inst.classValue()); - // sum of squared y values - nodeStatistics.addToValue(2, inst.classValue()*inst.classValue()); - - this.perceptron.trainOnInstance(inst); - if (this.predictionFunction != 1) { //Train target mean if prediction function is not Perceptron - this.targetMean.trainOnInstance(inst); - } - } + private static final long serialVersionUID = 3720878438856489690L; + + public RulePassiveRegressionNode(double[] statistics) { + super(statistics); + } + + public RulePassiveRegressionNode() { + super(); + } + + public RulePassiveRegressionNode(RuleRegressionNode activeLearningNode) { + this.predictionFunction = activeLearningNode.predictionFunction; + this.ruleNumberID = activeLearningNode.ruleNumberID; + this.nodeStatistics = new DoubleVector(activeLearningNode.nodeStatistics); + this.learningRatio = activeLearningNode.learningRatio; + this.perceptron = new Perceptron(activeLearningNode.perceptron, true); + this.targetMean = new TargetMean(activeLearningNode.targetMean); + } + + /* + * Update with input instance + */ + @Override + public void updateStatistics(Instance inst) { + // Update the statistics for this node + // number of instances passing through the node + nodeStatistics.addToValue(0, 1); + // sum of y values + nodeStatistics.addToValue(1, inst.classValue()); + // sum of squared y values + nodeStatistics.addToValue(2, inst.classValue() * inst.classValue()); + + this.perceptron.trainOnInstance(inst); + if (this.predictionFunction != 1) { // Train target mean if prediction + // function is not Perceptron + this.targetMean.trainOnInstance(inst); + } + } }
