Java tutorial
/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * WekaPredictionsToInstances.java * Copyright (C) 2009-2017 University of Waikato, Hamilton, New Zealand */ package adams.flow.transformer; import adams.data.statistics.StatUtils; import adams.flow.container.WekaEvaluationContainer; import adams.flow.core.Token; import weka.classifiers.CrossValidationHelper; import weka.classifiers.Evaluation; import weka.classifiers.evaluation.NominalPrediction; import weka.classifiers.evaluation.Prediction; import weka.core.Attribute; import weka.core.DenseInstance; import weka.core.Instances; import java.util.ArrayList; /** <!-- globalinfo-start --> * Generates weka.core.Instances from the predictions of an Evaluation object. * <br><br> <!-- globalinfo-end --> * <!-- flow-summary-start --> * Input/output:<br> * - accepts:<br> * weka.classifiers.Evaluation<br> * adams.flow.container.WekaEvaluationContainer<br> * - generates:<br> * weka.core.Instances<br> * <br><br> * Container information:<br> * - adams.flow.container.WekaEvaluationContainer: Evaluation, Model, Prediction output, Original indices * <br><br> <!-- flow-summary-end --> * <!-- options-start --> * <pre>-logging-level <OFF|SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST> (property: loggingLevel) * The logging level for outputting errors and debugging output. * default: WARNING * </pre> * * <pre>-name <java.lang.String> (property: name) * The name of the actor. * default: WekaPredictionsToInstances * </pre> * * <pre>-annotation <adams.core.base.BaseAnnotation> (property: annotations) * The annotations to attach to this actor. * default: * </pre> * * <pre>-skip <boolean> (property: skip) * If set to true, transformation is skipped and the input token is just forwarded * as it is. * default: false * </pre> * * <pre>-stop-flow-on-error <boolean> (property: stopFlowOnError) * If set to true, the flow execution at this level gets stopped in case this * actor encounters an error; the error gets propagated; useful for critical * actors. * default: false * </pre> * * <pre>-silent <boolean> (property: silent) * If enabled, then no errors are output in the console; Note: the enclosing * actor handler must have this enabled as well. * default: false * </pre> * * <pre>-add-index <boolean> (property: addLabelIndex) * If set to true, then the label is prefixed with the index. * default: false * </pre> * * <pre>-error <boolean> (property: showError) * If set to true, then the error will be displayed as well. * default: false * </pre> * * <pre>-absolute-error <boolean> (property: useAbsoluteError) * If set to true, then the error will be absolute (no direction). * default: true * </pre> * * <pre>-probability <boolean> (property: showProbability) * If set to true, then the probability of the prediction will be displayed * as well (only for nominal class attributes). * default: false * </pre> * * <pre>-distribution <boolean> (property: showDistribution) * If set to true, then the class distribution will be displayed as well (only * for nominal class attributes). * default: false * </pre> * * <pre>-weight <boolean> (property: showWeight) * If set to true, then the instance weight will be displayed as well. * default: false * </pre> * * <pre>-use-original-indices <boolean> (property: useOriginalIndices) * If set to true, the input token is a adams.flow.container.WekaEvaluationContainer * and it contains the original indices ('Original indices') then the output * will get aligned with the original data. * default: false * </pre> * * <pre>-test-attributes <adams.core.Range> (property: testAttributes) * The range of attributes from the test set to add to the output (if test * data available). * default: * example: A range is a comma-separated list of single 1-based indices or sub-ranges of indices ('start-end'); 'inv(...)' inverts the range '...'; the following placeholders can be used as well: first, second, third, last_2, last_1, last * </pre> * * <pre>-measures-prefix <java.lang.String> (property: measuresPrefix) * The prefix to use for the measure attributes being output. * default: * </pre> * <!-- options-end --> * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision$ */ public class WekaPredictionsToInstances extends AbstractWekaPredictionsTransformer { /** for serialization. */ private static final long serialVersionUID = -1552754008462778501L; /** * Returns a string describing the object. * * @return a description suitable for displaying in the gui */ @Override public String globalInfo() { return "Generates weka.core.Instances from the predictions of an Evaluation object."; } /** * Executes the flow item. * * @return null if everything is fine, otherwise error message */ @Override protected String doExecute() { String result; Evaluation eval; int i; int n; int indexErr; int indexProb; int indexDist; int indexWeight; boolean nominal; Instances header; ArrayList<Attribute> atts; ArrayList<String> values; ArrayList<Prediction> predictions; Prediction pred; double[] vals; Instances data; Instances testData; int[] indices; result = null; if (m_InputToken.getPayload() instanceof WekaEvaluationContainer) { eval = (Evaluation) ((WekaEvaluationContainer) m_InputToken.getPayload()) .getValue(WekaEvaluationContainer.VALUE_EVALUATION); indices = (int[]) ((WekaEvaluationContainer) m_InputToken.getPayload()) .getValue(WekaEvaluationContainer.VALUE_ORIGINALINDICES); testData = (Instances) ((WekaEvaluationContainer) m_InputToken.getPayload()) .getValue(WekaEvaluationContainer.VALUE_TESTDATA); } else { eval = (Evaluation) m_InputToken.getPayload(); indices = null; testData = null; } header = eval.getHeader(); nominal = header.classAttribute().isNominal(); predictions = eval.predictions(); if (predictions != null) { // create header atts = new ArrayList<>(); // actual if (nominal && m_AddLabelIndex) { values = new ArrayList<>(); for (i = 0; i < header.classAttribute().numValues(); i++) values.add((i + 1) + ":" + header.classAttribute().value(i)); atts.add(new Attribute(m_MeasuresPrefix + "Actual", values)); } else { atts.add(header.classAttribute().copy(m_MeasuresPrefix + "Actual")); } // predicted if (nominal && m_AddLabelIndex) { values = new ArrayList<>(); for (i = 0; i < header.classAttribute().numValues(); i++) values.add((i + 1) + ":" + header.classAttribute().value(i)); atts.add(new Attribute(m_MeasuresPrefix + "Predicted", values)); } else { atts.add(header.classAttribute().copy(m_MeasuresPrefix + "Predicted")); } // error indexErr = -1; if (m_ShowError) { indexErr = atts.size(); if (nominal) { values = new ArrayList<>(); values.add("n"); values.add("y"); atts.add(new Attribute(m_MeasuresPrefix + "Error", values)); } else { atts.add(new Attribute(m_MeasuresPrefix + "Error")); } } // probability indexProb = -1; if (m_ShowProbability && nominal) { indexProb = atts.size(); atts.add(new Attribute(m_MeasuresPrefix + "Probability")); } // distribution indexDist = -1; if (m_ShowDistribution && nominal) { indexDist = atts.size(); for (n = 0; n < header.classAttribute().numValues(); n++) atts.add(new Attribute( m_MeasuresPrefix + "Distribution (" + header.classAttribute().value(n) + ")")); } // weight indexWeight = -1; if (m_ShowWeight) { indexWeight = atts.size(); atts.add(new Attribute(m_MeasuresPrefix + "Weight")); } data = new Instances("Predictions", atts, predictions.size()); data.setClassIndex(1); // predicted // add data if ((indices != null) && m_UseOriginalIndices) predictions = CrossValidationHelper.alignPredictions(predictions, indices); for (i = 0; i < predictions.size(); i++) { pred = predictions.get(i); vals = new double[data.numAttributes()]; // actual vals[0] = pred.actual(); // predicted vals[1] = pred.predicted(); // error if (m_ShowError) { if (nominal) { vals[indexErr] = ((pred.actual() != pred.predicted()) ? 1.0 : 0.0); } else { if (m_UseAbsoluteError) vals[indexErr] = Math.abs(pred.actual() - pred.predicted()); else vals[indexErr] = pred.actual() - pred.predicted(); } } // probability if (m_ShowProbability && nominal) { vals[indexProb] = StatUtils.max(((NominalPrediction) pred).distribution()); } // distribution if (m_ShowDistribution && nominal) { for (n = 0; n < header.classAttribute().numValues(); n++) vals[indexDist + n] = ((NominalPrediction) pred).distribution()[n]; } // weight if (m_ShowWeight) { vals[indexWeight] = pred.weight(); } // add row data.add(new DenseInstance(1.0, vals)); } // add test data? if ((testData != null) && !m_TestAttributes.isEmpty()) { testData = filterTestData(testData); if (testData != null) data = Instances.mergeInstances(data, testData); } // generate output token m_OutputToken = new Token(data); } else { getLogger().severe("No predictions available from Evaluation object!"); } return result; } /** * Returns the class of objects that it generates. * * @return <!-- flow-generates-start -->weka.core.Instances.class<!-- flow-generates-end --> */ public Class[] generates() { return new Class[] { Instances.class }; } }