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/>. */ /* * WekaPredictionsToSpreadSheet.java * Copyright (C) 2013-2018 University of Waikato, Hamilton, New Zealand */ package adams.flow.transformer; import adams.core.ClassCrossReference; import adams.data.spreadsheet.DefaultSpreadSheet; import adams.data.spreadsheet.Row; import adams.data.spreadsheet.SpreadSheet; import adams.data.statistics.StatUtils; import adams.flow.container.WekaEvaluationContainer; import adams.flow.core.Token; import adams.ml.data.InstancesView; import weka.classifiers.CrossValidationHelper; import weka.classifiers.Evaluation; import weka.classifiers.evaluation.NominalPrediction; import weka.classifiers.evaluation.Prediction; import weka.core.Instances; import java.util.ArrayList; /** <!-- globalinfo-start --> * Generates a SpreadSheet object from the predictions of an Evaluation object.<br> * <br> * See also:<br> * adams.flow.transformer.WekaSpreadSheetToPredictions * <br><br> <!-- globalinfo-end --> * <!-- flow-summary-start --> * Input/output:<br> * - accepts:<br> * weka.classifiers.Evaluation<br> * adams.flow.container.WekaEvaluationContainer<br> * - generates:<br> * adams.data.spreadsheet.SpreadSheet<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: WekaPredictionsToSpreadSheet * </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) */ public class WekaPredictionsToSpreadSheet extends AbstractWekaPredictionsTransformer implements ClassCrossReference { /** 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 a SpreadSheet object from the predictions of an Evaluation object."; } /** * Returns the cross-referenced classes. * * @return the classes */ public Class[] getClassCrossReferences() { return new Class[] { WekaSpreadSheetToPredictions.class }; } /** * 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<Prediction> predictions; Prediction pred; SpreadSheet data; Instances testData; InstancesView testView; Row row; 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) { data = new DefaultSpreadSheet(); data.setName("Predictions"); // create header row = data.getHeaderRow(); row.addCell("A").setContent(m_MeasuresPrefix + "Actual"); row.addCell("P").setContent(m_MeasuresPrefix + "Predicted"); indexErr = -1; if (m_ShowError) { indexErr = row.getCellCount(); row.addCell("E").setContent(m_MeasuresPrefix + "Error"); } // probability indexProb = -1; if (m_ShowProbability && nominal) { indexProb = row.getCellCount(); row.addCell("Pr").setContent(m_MeasuresPrefix + "Probability"); } // distribution indexDist = -1; if (m_ShowDistribution && nominal) { indexDist = row.getCellCount(); for (n = 0; n < header.classAttribute().numValues(); n++) row.addCell("D" + n).setContent( m_MeasuresPrefix + "Distribution (" + header.classAttribute().value(n) + ")"); } // weight indexWeight = -1; if (m_ShowWeight) { indexWeight = row.getCellCount(); row.addCell("W").setContent(m_MeasuresPrefix + "Weight"); } // add data if ((indices != null) && m_UseOriginalIndices) predictions = CrossValidationHelper.alignPredictions(predictions, indices); for (i = 0; i < predictions.size(); i++) { pred = predictions.get(i); row = data.addRow(); // actual if (Double.isNaN(pred.actual())) row.addCell(0).setMissing(); else if (nominal) row.addCell(0).setContentAsString(header.classAttribute().value((int) pred.actual())); else row.addCell(0).setContent(pred.actual()); // predicted if (Double.isNaN(pred.predicted())) row.addCell(1).setMissing(); else if (nominal) row.addCell(1).setContentAsString(header.classAttribute().value((int) pred.predicted())); else row.addCell(1).setContent(pred.predicted()); // error if (m_ShowError) { if (nominal) { row.addCell(indexErr).setContent((pred.actual() != pred.predicted() ? "true" : "false")); } else { if (m_UseAbsoluteError) row.addCell(indexErr).setContent(Math.abs(pred.actual() - pred.predicted())); else row.addCell(indexErr).setContent(pred.actual() - pred.predicted()); } } // probability if (m_ShowProbability && nominal) { row.addCell(indexProb).setContent(StatUtils.max(((NominalPrediction) pred).distribution())); } // distribution if (m_ShowDistribution && nominal) { for (n = 0; n < header.classAttribute().numValues(); n++) row.addCell(indexDist + n).setContent(((NominalPrediction) pred).distribution()[n]); } // weight if (m_ShowWeight) { row.addCell(indexWeight).setContent(pred.weight()); } } // add test data? if ((testData != null) && !m_TestAttributes.isEmpty()) { testData = filterTestData(testData); if (testData != null) { testView = new InstancesView(testData); data.mergeWith(testView); } } // 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 -->adams.data.spreadsheet.SpreadSheet.class<!-- flow-generates-end --> */ public Class[] generates() { return new Class[] { SpreadSheet.class }; } }