/* * Copyright (c) 2010 Pentaho Corporation. All rights reserved. * This software was developed by Pentaho Corporation and is provided under the terms * of the GNU Lesser General Public License, Version 2.1. You may not use * this file except in compliance with the license. If you need a copy of the license, * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is Time Series * Forecasting. The Initial Developer is Pentaho Corporation. * * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to * the license for the specific language governing your rights and limitations. */ /* * AdvancedConfigPanel.java * Copyright (C) 2010 Pentaho Corporation */ package weka.classifiers.timeseries.gui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.table.DefaultTableModel; import weka.classifiers.Classifier; import weka.classifiers.timeseries.WekaForecaster; import weka.classifiers.timeseries.core.CustomPeriodicTest; import weka.classifiers.timeseries.core.OverlayForecaster; import weka.classifiers.timeseries.core.TSLagMaker; import weka.classifiers.timeseries.eval.TSEvalModule; import weka.classifiers.timeseries.eval.TSEvaluation; import weka.core.Attribute; import weka.core.Capabilities; import weka.core.Capabilities.Capability; import weka.core.Instances; import weka.core.Range; import weka.core.SerializedObject; import weka.gui.AttributeSelectionPanel; import weka.gui.ExtensionFileFilter; import weka.gui.GenericObjectEditor; import weka.gui.PropertyPanel; public class AdvancedConfigPanel extends JPanel { /** * For serialization */ private static final long serialVersionUID = 5465960083615138964L; /** The training instances to operate on */ protected Instances m_instances; /** A reference to the simple config panel */ protected SimpleConfigPanel m_simpleConfig; /** A tabbed pane to hold the individual advanced configuration panels */ JTabbedPane m_configHolder = new JTabbedPane(); /** Editor for selecting and configuring the base algorithm */ protected GenericObjectEditor m_baseLearnerEditor = new GenericObjectEditor(); /** Property panel for editing base algorithm */ protected PropertyPanel m_baseLearnerPanel = new PropertyPanel(m_baseLearnerEditor); /** Custom lags checkbox */ protected JCheckBox m_useCustomLags = new JCheckBox("Use custom lag lengths"); /** Min lag spinner */ protected JSpinner m_minLagSpinner; /** Max lag spinner */ protected JSpinner m_maxLagSpinner; /** Adjust for variance check box */ protected JCheckBox m_adjustForVarianceCheckBox = new JCheckBox("Adjust for variance"); /** Field for fine tuning the lags that are created by specifying a range */ protected JTextField m_fineTuneLagsField = new JTextField(); /** Check box for averaging consecutive long lags */ protected JCheckBox m_averageLongLags = new JCheckBox("Average consecutive long lags"); /** Spinner for selecting which lag to start averaging from */ protected JSpinner m_averageLagsAfter; /** Spinner for selecting how many consecutive long lags to average into one new field */ protected JSpinner m_numConsecutiveToAverage; /** Data structure for holding the field names for date-derived fields */ protected Instances m_dateDerivedPeriodicsHeader; /** Custom date-derived fields check box */ protected JCheckBox m_customizeDateDerivedPeriodics = new JCheckBox("Customize"); /** Edit button for custom date-derived fields */ protected JButton m_editCustomPeriodicBut = new JButton("Edit"); /** Add button for custom date-derived fields */ protected JButton m_addCustomPeriodicBut = new JButton("New"); /** Delete button for custom date-derived fields */ protected JButton m_deleteCustomPeriodicBut = new JButton("Delete"); /** Save button for saving date-derived periodics to a file */ protected JButton m_savePeriodicBut = new JButton("Save"); /** Load button for loading pre-defined date-derived periodics from a file */ protected JButton m_loadPeriodicBut = new JButton("Load"); /** File chooser for saving/loading date-derived periodics */ protected JFileChooser m_fileChooser; /** Map of custom date-derived fields */ protected Map<String, ArrayList<CustomPeriodicTest>> m_customPeriodics = new HashMap<String, ArrayList<CustomPeriodicTest>>(); protected static final int NUM_PREDEFINED_PERIODICS = 7; /** * Inner class extending AttributeSelectionPanel that adds methods * to get the encapsulated JTable and clear the current table model. */ protected class AttributeSelectionPanelExtended extends AttributeSelectionPanel { /** For serialization */ private static final long serialVersionUID = -6863797282164060690L; public AttributeSelectionPanelExtended(boolean include, boolean remove, boolean invert, boolean pattern) { super(include, remove, invert, pattern); } public JTable getTable() { return m_Table; } public void clearTableModel() { m_Model = null; m_Table.setModel(new DefaultTableModel()); m_Table.revalidate(); m_Table.repaint(); } } /** Panel for holding and selecting date-derived periodic attributes */ protected AttributeSelectionPanelExtended m_dateDerivedPeriodicSelector = new AttributeSelectionPanelExtended(false, false, false, false); /** Non date-based primary periodic stuff */ protected JComboBox m_primaryPeriodicCombo = new JComboBox(); /** Panel for holding and selecting overlay fields */ protected AttributeSelectionPanelExtended m_overlaySelector = new AttributeSelectionPanelExtended(true, true, true, true); /** Check box for overlay fields */ protected JCheckBox m_useOverlayData = new JCheckBox("Use overlay data"); /** Holds the structure of overlay fields */ protected Instances m_overlayHeader; /** Holds the names of the currently selected evaluation modules */ protected Instances m_evaluationModsHeader; /** Panel for holding and selecting evaluation modules */ protected AttributeSelectionPanel m_evaluationMetrics = new AttributeSelectionPanel(false, false, false, false); /** Perform training set evaluation check box */ protected JCheckBox m_trainingCheckBox = new JCheckBox("Evaluate on training"); /** Perform hold-out evaluation check box */ protected JCheckBox m_holdoutCheckBox = new JCheckBox("Evaluate on held out training"); /** Text field for setting the size of the hold-out set */ protected JTextField m_holdoutSize = new JTextField(); /** show the separate test set checkbox and button? */ protected boolean m_allowSeparateTestSet = true; /** Separate test set check box */ protected JCheckBox m_separateTestSetCheckBox = new JCheckBox("Evaluate on a separate test set"); /** Button for selecting a separate test set */ protected JButton m_testSetBut = new JButton("Separate test set"); /** Check box for outputting predictions */ protected JCheckBox m_outputPredsCheckBox = new JCheckBox("Output predictions at step"); /** Combo box for selecting which target to output predictions for */ protected JComboBox m_outputPredsCombo = new JComboBox(); protected JLabel m_outputPredsComboLabel = new JLabel("Target to output", JLabel.RIGHT); /** Spinner for selecting which step to output */ protected JSpinner m_outputStepSpinner; protected JLabel m_outputStepLabel = new JLabel("Step to output", JLabel.RIGHT); /** Output future predictions check box */ protected JCheckBox m_outputFutureCheckBox = new JCheckBox("Output future predictions beyond end of series "); /** Graph predictions at step check box */ protected JCheckBox m_graphPredsAtStepCheckBox = new JCheckBox("Graph predictions at step"); /** Spinner for selecting which step to graph predictions at */ protected JSpinner m_graphPredsAtStepSpinner; protected JLabel m_stepLab = new JLabel("Steps to graph"); /** Graph targets for specific step */ protected JCheckBox m_graphTargetForStepsCheckBox = new JCheckBox("Graph target at steps:"); /** Graph target at steps combo box */ protected JComboBox m_graphTargetAtStepsCombo = new JComboBox(); protected JLabel m_targetComboLabel = new JLabel("Target to graph", JLabel.RIGHT); /** Text field for specifying a range of steps to graph for the selected target */ protected JTextField m_stepRange = new JTextField("1"); /** Graph future predictions check box */ protected JCheckBox m_graphFutureCheckBox = new JCheckBox("Graph future predictions beyond end of series"); static { GenericObjectEditor.registerEditors(); } /** * Get a title for displaying in the tab that will hold this panel * * @return a title for this configuration panel */ public String getTabTitle() { return "Advanced configuration"; } /** * Get the tool tip for this configuration panel * * @return the tool tip for this configuration panel */ public String getTabTitleToolTip() { return "Advanced configuration"; } /** * Get the underlying Weka classifier that will be used to make the * predictions * * @return the underlying Weka classifier */ public Classifier getBaseClassifier() { return (Classifier)m_baseLearnerEditor.getValue(); } /** * Set the instances that will be used in the training and evaluation of * the forecaster * * @param train the instances to use in the training and evaluation process */ public void setInstances(Instances train) { m_instances = train; updatePanel(); } /** * Set the enabled/disabled status of date-derived periodic panel * and its associated widgets. * * @param s true if date-derived periodicis is to be enabled */ public void enableDateDerivedPeriodics(boolean s) { m_customizeDateDerivedPeriodics.setEnabled(s); if (!s) { m_customizeDateDerivedPeriodics.setSelected(false); m_addCustomPeriodicBut.setEnabled(false); m_editCustomPeriodicBut.setEnabled(false); m_deleteCustomPeriodicBut.setEnabled(false); m_savePeriodicBut.setEnabled(false); m_loadPeriodicBut.setEnabled(false); } } /** * Returns true if date-derived periodics is enabled * * @return if date-derived periodics is enabled. */ public boolean isEnabledCustomizeDateDerivedPeriodics() { return m_customizeDateDerivedPeriodics.isEnabled(); } /** * Returns true if the date-derived periodics check box is selected. * * @return true if the date-derived periodics check box is selected. */ public boolean getCustomizeDateDerivedPeriodics() { return m_customizeDateDerivedPeriodics.isSelected(); } /** * Returns true if the user has opted to customize the lags. * * @return true if custom lags are in use. */ public boolean isUsingCustomLags() { return m_useCustomLags.isSelected(); } /** * Gets the size of the holdout set. * * @return the size of the holdout set or 0 if no holdout set is being used. */ public double getHoldoutSetSize() { double result = 0; if (m_holdoutCheckBox.isSelected()) { try { result = Double.parseDouble(m_holdoutSize.getText()); } catch (NumberFormatException ex) {} } return result; } /** * Returns true if the user has opted to output future predictions * * @return if the user has opted to output future predictions */ public boolean getOutputFuturePredictions() { return m_outputFutureCheckBox.isSelected(); } /** * Returns at which step to output predictions. Returns * 0 if the user has not opted to output predictions. * * @return step at which to output predictions or 0 if * no predictions are to be output. */ public int getOutputPredictionsAtStep() { if (!m_outputPredsCheckBox.isSelected()) { return 0; } return ((SpinnerNumberModel)m_outputStepSpinner. getModel()).getNumber().intValue(); } /** * Returns true if the user has opted to graph a target at * specified steps * * @return true if the user has opted to graph a target at * specified steps */ public boolean getGraphTargetForSteps() { return m_graphTargetForStepsCheckBox.isSelected(); } /** * Return the target that is to be graphed at various * steps * * @return the target that is to be graphed at specified steps or * null if the user has not opted to graph a targert at specified * steps */ public String getGraphTargetForStepsTarget() { if (!getGraphTargetForSteps()) { return null; } return m_graphTargetAtStepsCombo.getSelectedItem().toString(); } /** * If the user has opted to graph a target a various steps, then this * method returns the list of steps that they have selected. * * @return the list of steps at which to graph a target, or null if the * user has not opted to graph a target at various steps. */ public List<Integer> getGraphTargetForStepsStepList() { String rng = m_stepRange.getText(); if (rng == null || rng.length() == 0) { return null; } Range range = new Range(rng); range.setUpper(m_simpleConfig.getHorizonValue()); int[] indices = range.getSelection(); List<Integer> rangeList = new ArrayList<Integer>(); for (int i : indices) { rangeList.add((i + 1)); } return rangeList; } /** * Get the selected target to output predictions for. Returns * null if the user has not opted to output predictions. * * @return the name of the target to output predictions for or * null if no predictions are to be output. */ public String getOutputPredictionsTarget() { if (!m_outputPredsCheckBox.isSelected()) { return null; } return m_outputPredsCombo.getSelectedItem().toString(); } /** * Get the step number to graph all the targets at. * * @return the step number to graph all the targets at, or * 0 if the user has not opted to graph all the targets. */ public int getGraphPredictionsAtStep() { if (!m_graphPredsAtStepCheckBox.isSelected()) { return 0; } return ((SpinnerNumberModel)m_graphPredsAtStepSpinner. getModel()).getNumber().intValue(); } /** * Returns true if the user has opted to graph future predictions * * @return true if the user has opted graph future predictions */ public boolean getGraphFuturePredictions() { return m_graphFutureCheckBox.isSelected(); } /** * Constructor * * @param s a reference to the simple configuration panel * @param allowSeparateTestSet true if the separate test set button * is to be displayed */ public AdvancedConfigPanel(SimpleConfigPanel s, boolean allowSeparateTestSet) { m_allowSeparateTestSet = allowSeparateTestSet; m_simpleConfig = s; setLayout(new BorderLayout()); layoutLearnerPanel(); layoutLagPanel(); layoutDateDerivedPeriodicPanel(); layoutOverlayPanel(); layoutEvaluationPanel(); layoutOutputPanel(); add(m_configHolder, BorderLayout.CENTER); } /** * Constructor * * @param s a reference to the simple configuration panel */ public AdvancedConfigPanel(SimpleConfigPanel s) { this(s, true); } /** * Updates various enabled/selected status of widgets based on the current * configuration */ public void updatePanel() { updateDateDerivedPanel(); updatePrimaryPeriodic(); updateOutputPanel(); updateOverlayPanel(); } /** * Updates the status/selection of widgets on the overlay panel */ public void updateOverlayPanel() { Instances newI = createAvailableOverlayList(); if (newI == null) { m_useOverlayData.setSelected(false); m_useOverlayData.setEnabled(false); m_overlaySelector.clearTableModel(); } else { m_useOverlayData.setEnabled(true); if (m_useOverlayData.isSelected()) { if (m_overlayHeader == null || !newI.equalHeaders(m_overlayHeader)) { m_overlayHeader = newI; m_overlaySelector.setInstances(newI); } } } } private Instances createAvailableOverlayList() { String ppfn = m_primaryPeriodicCombo.getSelectedItem().toString(); Instances result = null; if (m_simpleConfig.m_targetHeader != null) { ArrayList<Attribute> availableAtts = new ArrayList<Attribute>(); int[] selectedTargets = m_simpleConfig.m_targetPanel.getSelectedAttributes(); for (int i = 0; i < m_instances.numAttributes(); i++) { // skip all date attributes if (m_instances.attribute(i).isDate()) { continue; } // skip any primary periodic if (m_instances.attribute(i).name().equals(ppfn)) { continue; } if (m_simpleConfig.m_targetHeader. attribute(m_instances.attribute(i).name()) != null) { // now need to check whether it's been selected as a target int indexToCheck = m_simpleConfig.m_targetHeader. attribute(m_instances.attribute(i).name()).index(); boolean ok = true; for (int j = 0; j < selectedTargets.length; j++) { if (indexToCheck == selectedTargets[j]) { ok = false; // can't use this attribute break; } } if (ok) { availableAtts.add(new Attribute(m_instances.attribute(i).name())); } } else { // this is available availableAtts.add(new Attribute(m_instances.attribute(i).name())); } } if (availableAtts.size() > 0) { result = new Instances("Overlay",availableAtts, 1); } } return result; } /** * Updates the status/selection of various widgets on the output panel */ public void updateOutputPanel() { if (m_simpleConfig.m_targetHeader != null) { // configure the target combos Vector<String> candidates = new Vector<String>(); for (int i = 0; i < m_simpleConfig.m_targetHeader.numAttributes(); i++) { candidates.add(m_simpleConfig.m_targetHeader.attribute(i).name()); } m_graphTargetAtStepsCombo.setModel(new DefaultComboBoxModel(candidates)); m_outputPredsCombo.setModel(new DefaultComboBoxModel(candidates)); } } /** * Updates the status/selection of various widgets on the date-derived * periodics panel */ protected void updateDateDerivedPanel() { if (m_simpleConfig.m_timeStampCombo.getSelectedItem() == null) { return; } String selectedTimeStamp = m_simpleConfig.m_timeStampCombo.getSelectedItem().toString(); if (selectedTimeStamp.equals("<None>") || selectedTimeStamp.equals("<Use and artificial time stamp>")) { m_customizeDateDerivedPeriodics.setSelected(false); m_customizeDateDerivedPeriodics.setEnabled(false); m_editCustomPeriodicBut.setEnabled(false); m_addCustomPeriodicBut.setEnabled(false); m_deleteCustomPeriodicBut.setEnabled(false); m_savePeriodicBut.setEnabled(false); m_loadPeriodicBut.setEnabled(false); } else if (m_instances != null) { Attribute timeStampAtt = m_instances.attribute(selectedTimeStamp); if (timeStampAtt != null && timeStampAtt.isDate()) { m_customizeDateDerivedPeriodics.setEnabled(true); } else { m_customizeDateDerivedPeriodics.setSelected(false); m_customizeDateDerivedPeriodics.setEnabled(false); m_editCustomPeriodicBut.setEnabled(false); m_addCustomPeriodicBut.setEnabled(false); m_deleteCustomPeriodicBut.setEnabled(false); m_savePeriodicBut.setEnabled(false); m_loadPeriodicBut.setEnabled(false); } } else { m_customizeDateDerivedPeriodics.setSelected(false); m_customizeDateDerivedPeriodics.setEnabled(false); m_editCustomPeriodicBut.setEnabled(false); m_addCustomPeriodicBut.setEnabled(false); m_deleteCustomPeriodicBut.setEnabled(false); m_savePeriodicBut.setEnabled(false); m_loadPeriodicBut.setEnabled(false); } } /** * Sets up the primary periodic drop-down box */ protected void updatePrimaryPeriodic() { Vector<String> entries = new Vector<String>(); entries.add("<None>"); if (m_instances != null) { for (int i = 0; i < m_instances.numAttributes(); i++) { if (m_instances.attribute(i).isNominal()) { entries.add(m_instances.attribute(i).name()); } } } m_primaryPeriodicCombo.setModel(new DefaultComboBoxModel(entries)); } /** * Updates the status of eval and output widgets */ protected void updateEvalAndOutputEnabledStatus() { boolean enable = (m_trainingCheckBox.isSelected() || m_holdoutCheckBox.isSelected() || m_separateTestSetCheckBox.isSelected()); // enable/disable and deselect all prediction and graphing widgets m_outputPredsCheckBox.setEnabled(enable); //m_outputFutureCheckBox.setEnabled(enable); m_graphPredsAtStepCheckBox.setEnabled(enable); //m_outputStepSpinner.setEnabled(enable); //m_graphPredsAtStepSpinner.setEnabled(enable); m_graphTargetForStepsCheckBox.setEnabled(enable); //m_graphFutureCheckBox.setEnabled(enable); if (!enable) { m_outputPredsCheckBox.setSelected(false); // m_outputFutureCheckBox.setSelected(false); m_graphPredsAtStepCheckBox.setSelected(false); m_graphTargetForStepsCheckBox.setSelected(false); //m_graphFutureCheckBox.setSelected(false); } boolean enabled = m_graphTargetForStepsCheckBox.isSelected(); m_stepLab.setEnabled(enabled); m_stepRange.setEnabled(enabled); m_targetComboLabel.setEnabled(enabled); m_graphTargetAtStepsCombo.setEnabled(enabled); m_graphPredsAtStepSpinner.setEnabled(enabled); enabled = m_outputPredsCheckBox.isSelected(); m_outputStepLabel.setEnabled(enabled); m_outputPredsCombo.setEnabled(enabled); m_outputPredsComboLabel.setEnabled(enable); m_outputStepSpinner.setEnabled(enabled); m_testSetBut.setEnabled(!m_holdoutCheckBox.isSelected()); m_separateTestSetCheckBox.setEnabled(!m_holdoutCheckBox.isSelected()); m_holdoutSize.setEnabled(m_holdoutCheckBox.isSelected()); if (m_holdoutCheckBox.isSelected()) { m_separateTestSetCheckBox.setSelected(false); } } /** * Layout the evaluation panel */ protected void layoutEvaluationPanel() { JPanel basePanel = new JPanel(); basePanel.setLayout(new BorderLayout()); /*basePanel.setBorder(BorderFactory. createTitledBorder("Evaluation")); */ JPanel base1 = new JPanel(); base1.setLayout(new BorderLayout()); base1.add(m_evaluationMetrics, BorderLayout.CENTER); List<TSEvalModule> evalModulesL = TSEvalModule.getModuleList(); ArrayList<Attribute> atts = new ArrayList<Attribute>(); int numMods = 0; for (TSEvalModule s : evalModulesL) { if (!(s.getEvalName().equals("Error"))) { atts.add(new Attribute(s.toString())); numMods++; } } Instances modInsts = new Instances("Eval modules", atts, 1); m_evaluationModsHeader = modInsts; m_evaluationMetrics.setInstances(modInsts); boolean[] selected = new boolean[numMods]; selected[0] = true; selected[2] = true; try { m_evaluationMetrics.setSelectedAttributes(selected); } catch (Exception ex) {} m_evaluationMetrics.setPreferredScrollableViewportSize(new Dimension(260,80)); m_evaluationMetrics.setBorder(BorderFactory.createTitledBorder("Metrics")); JPanel temp1 = new JPanel(); temp1.setLayout(new BorderLayout()); temp1.setBorder(BorderFactory.createTitledBorder("Test options")); temp1.add(m_trainingCheckBox, BorderLayout.NORTH); //m_trainingCheckBox.setSelected(true); m_trainingCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateEvalAndOutputEnabledStatus(); if (m_simpleConfig != null) { m_simpleConfig.m_performEvaluation. setSelected(m_trainingCheckBox.isSelected() || m_holdoutCheckBox.isSelected()); } } }); JPanel temp2 = new JPanel(); temp2.setLayout(new BorderLayout()); temp2.add(m_holdoutCheckBox, BorderLayout.WEST); temp2.add(m_holdoutSize, BorderLayout.EAST); m_holdoutSize.setEnabled(false); int width = m_minLagSpinner.getPreferredSize().width; int height = m_minLagSpinner.getPreferredSize().height; m_holdoutSize.setPreferredSize(new Dimension(width * 1, height)); m_holdoutSize.setMinimumSize(new Dimension(width * 1, height)); m_holdoutSize.setToolTipText("Number of instances (value >=1) or percentage " + "(value < 1) to hold out from the end of the data"); m_holdoutSize.setText("0.3"); m_holdoutCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateEvalAndOutputEnabledStatus(); if (m_simpleConfig != null) { m_simpleConfig.m_performEvaluation. setSelected(m_trainingCheckBox.isSelected() || m_holdoutCheckBox.isSelected()); } } }); temp1.add(temp2, BorderLayout.CENTER); if (m_allowSeparateTestSet) { JPanel checkAndButHolder = new JPanel(); checkAndButHolder.setLayout(new BorderLayout()); checkAndButHolder.add(m_separateTestSetCheckBox, BorderLayout.NORTH); checkAndButHolder.add(m_testSetBut, BorderLayout.SOUTH); temp1.add(checkAndButHolder, BorderLayout.SOUTH); m_separateTestSetCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { updateEvalAndOutputEnabledStatus(); } }); } JPanel temp3 = new JPanel(); temp3.setLayout(new BorderLayout()); temp3.add(temp1, BorderLayout.NORTH); base1.add(temp3, BorderLayout.EAST); basePanel.add(base1, BorderLayout.NORTH); //basePanel.add(outputOptsHolder, BorderLayout.EAST); m_testSetBut.setToolTipText("Evaluate on a separate test set"); m_testSetBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // TODO } }); //holder.add(basePanel, BorderLayout.EAST); m_configHolder.addTab("Evaluation", null, basePanel, "Evaluation options"); } /** * Layout the output panel */ protected void layoutOutputPanel() { JPanel outputOptsHolder = new JPanel(); outputOptsHolder.setLayout(new GridLayout(1,2)); JPanel textOutHolder = new JPanel(); textOutHolder.setLayout(new BorderLayout()); textOutHolder.setBorder(BorderFactory.createTitledBorder("Output options")); SpinnerNumberModel snm = new SpinnerNumberModel(); snm.setValue(1); snm.setMinimum(1); m_outputStepSpinner = new JSpinner(snm); Dimension spinD = m_outputStepSpinner.getPreferredSize(); spinD = new Dimension((int)(spinD.getWidth() * 1.5), (int)spinD.getHeight()); m_outputStepSpinner.setPreferredSize(spinD); JPanel checkHolder = new JPanel(); checkHolder.setLayout(new BorderLayout()); checkHolder.add(m_outputPredsCheckBox, BorderLayout.WEST); //labAndSpinnerHolder.add(m_outputStepSpinner, BorderLayout.EAST); JPanel comboAndSpinnerHolder = new JPanel(); comboAndSpinnerHolder.setLayout(new BorderLayout()); JPanel combo1Holder = new JPanel(); combo1Holder.setLayout(new BorderLayout()); combo1Holder.setBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0)); combo1Holder.add(m_outputPredsCombo, BorderLayout.EAST); combo1Holder.add(m_outputPredsComboLabel, BorderLayout.CENTER); comboAndSpinnerHolder.add(combo1Holder, BorderLayout.NORTH); JPanel spinnerHolder1 = new JPanel(); spinnerHolder1.setLayout(new BorderLayout()); spinnerHolder1.add(m_outputStepSpinner, BorderLayout.EAST); spinnerHolder1.add(m_outputStepLabel, BorderLayout.CENTER); JPanel spinnerHolder2 = new JPanel(); spinnerHolder2.setLayout(new BorderLayout()); spinnerHolder2.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0)); spinnerHolder2.add(spinnerHolder1, BorderLayout.NORTH); comboAndSpinnerHolder.add(spinnerHolder2, BorderLayout.CENTER); textOutHolder.add(comboAndSpinnerHolder, BorderLayout.CENTER); textOutHolder.add(checkHolder, BorderLayout.NORTH); m_outputStepSpinner.setEnabled(false); m_outputStepLabel.setEnabled(false); m_outputPredsCombo.setEnabled(false); m_outputPredsCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_outputStepSpinner.setEnabled(m_outputPredsCheckBox.isSelected()); m_outputStepLabel.setEnabled(m_outputPredsCheckBox.isSelected()); m_outputPredsComboLabel.setEnabled(m_outputPredsCheckBox.isSelected()); m_outputPredsCombo.setEnabled(m_outputPredsCheckBox.isSelected()); } }); JPanel temp1 = new JPanel(); temp1.setLayout(new BorderLayout()); temp1.add(m_outputFutureCheckBox, BorderLayout.NORTH); textOutHolder.add(temp1, BorderLayout.SOUTH); outputOptsHolder.add(textOutHolder); m_outputFutureCheckBox.setSelected(true); JPanel graphOutputHolder = new JPanel(); graphOutputHolder.setLayout(new BorderLayout()); graphOutputHolder.setBorder(BorderFactory. createTitledBorder("Graphing options")); outputOptsHolder.add(graphOutputHolder); snm = new SpinnerNumberModel(); snm.setValue(1); snm.setMinimum(1); m_graphPredsAtStepSpinner = new JSpinner(snm); spinD = m_graphPredsAtStepSpinner.getPreferredSize(); spinD = new Dimension((int)(spinD.getWidth() * 1.5), (int)spinD.getHeight()); m_graphPredsAtStepSpinner.setPreferredSize(spinD); JPanel labAndSpinnerHolder = new JPanel(); labAndSpinnerHolder.setLayout(new BorderLayout()); labAndSpinnerHolder.add(m_graphPredsAtStepCheckBox, BorderLayout.WEST); labAndSpinnerHolder.add(m_graphPredsAtStepSpinner, BorderLayout.EAST); graphOutputHolder.add(labAndSpinnerHolder, BorderLayout.NORTH); m_graphPredsAtStepCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { m_graphPredsAtStepSpinner. setEnabled(m_graphPredsAtStepCheckBox.isSelected()); } }); m_graphPredsAtStepSpinner.setEnabled(false); JPanel comboAndRangeHolder = new JPanel(); comboAndRangeHolder.setLayout(new BorderLayout()); comboAndRangeHolder.add(m_graphTargetForStepsCheckBox, BorderLayout.NORTH); JPanel temp2 = new JPanel(); temp2.setLayout(new BorderLayout()); temp2.setBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0)); temp2.add(m_graphTargetAtStepsCombo, BorderLayout.EAST); temp2.add(m_targetComboLabel, BorderLayout.CENTER); JPanel temp3 = new JPanel(); temp3.setLayout(new BorderLayout()); temp3.add(temp2, BorderLayout.NORTH); JPanel textHolder = new JPanel(); textHolder.setLayout(new BorderLayout()); //textHolder.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0)); textHolder.add(m_stepRange, BorderLayout.EAST); m_stepRange.setPreferredSize(new Dimension((int)spinD.getWidth() * 2, (int)spinD.getHeight())); m_stepLab.setToolTipText("Comma separated list of step numbers to graph"); m_stepRange.setToolTipText("Comma separated list of step numbers to graph"); JPanel ll = new JPanel(); ll.setLayout(new BorderLayout()); ll.add(m_stepLab, BorderLayout.EAST); textHolder.add(ll, BorderLayout.CENTER); temp3.add(textHolder, BorderLayout.CENTER); JPanel ll2 = new JPanel(); ll2.setLayout(new BorderLayout()); ll2.add(temp3, BorderLayout.NORTH); comboAndRangeHolder.add(ll2, BorderLayout.CENTER); comboAndRangeHolder.add(m_graphFutureCheckBox, BorderLayout.SOUTH); m_graphFutureCheckBox.setSelected(true); m_stepLab.setEnabled(false); m_stepRange.setEnabled(false); m_targetComboLabel.setEnabled(false); m_graphTargetAtStepsCombo.setEnabled(false); m_graphTargetForStepsCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean enabled = m_graphTargetForStepsCheckBox.isSelected(); m_stepLab.setEnabled(enabled); m_stepRange.setEnabled(enabled); m_targetComboLabel.setEnabled(enabled); m_graphTargetAtStepsCombo.setEnabled(enabled); } }); graphOutputHolder.add(comboAndRangeHolder, BorderLayout.CENTER); m_configHolder.addTab("Output", null, outputOptsHolder, "Configure output"); } private Instances createDateDerivedPeriodicList() { ArrayList<Attribute> atts = new ArrayList<Attribute>(); atts.add(new Attribute("AM")); atts.add(new Attribute("DayOfWeek")); atts.add(new Attribute("DayOfMonth")); atts.add(new Attribute("NumDaysInMonth")); atts.add(new Attribute("Weekend")); atts.add(new Attribute("Month")); atts.add(new Attribute("Quarter")); // Custom periodics for (String name : m_customPeriodics.keySet()) { atts.add(new Attribute("c_" + name)); } Instances insts = new Instances("Periodics", atts, 1); return insts; } private String displayAddEditDialog(List<CustomPeriodicTest> testList, String fieldName) { CustomPeriodicEditor ed = new CustomPeriodicEditor(testList); if (fieldName != null && fieldName.length() > 0) { ed.setFieldName(fieldName); } int result = JOptionPane.showConfirmDialog(this, ed, "Add/Edit custom periodic field", JOptionPane.OK_CANCEL_OPTION); if (result == JOptionPane.OK_OPTION) { if (testList.size() == 0) { // Nothing added to the list, so just cancel return ""; } return ed.getFieldName(); } else { return ""; // indicates cancel } } /** * Layout the overlay panel */ protected void layoutOverlayPanel() { JPanel basePanel = new JPanel(); basePanel.setLayout(new BorderLayout()); JPanel temp = new JPanel(); temp.setLayout(new BorderLayout()); //temp JPanel checkHolder = new JPanel(); checkHolder.setLayout(new BorderLayout()); checkHolder.add(m_useOverlayData, BorderLayout.NORTH); m_useOverlayData.setEnabled(false); temp.add(checkHolder, BorderLayout.EAST); temp.add(m_overlaySelector, BorderLayout.CENTER); m_overlaySelector.setPreferredScrollableViewportSize(new Dimension(250,70)); JPanel botP = new JPanel(); botP.setLayout(new BorderLayout()); botP.setBorder(BorderFactory. createTitledBorder("Overlay data selection")); botP.add(temp, BorderLayout.CENTER); m_useOverlayData.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_instances != null && m_useOverlayData.isSelected()) { if (m_overlaySelector.getSelectionModel() != null) { if (m_overlayHeader == null){ m_overlayHeader = createAvailableOverlayList(); } else { Instances newI = createAvailableOverlayList(); if (newI == null) { m_overlaySelector.clearTableModel(); m_overlayHeader = null; return; } else if (!newI.equalHeaders(m_overlayHeader)) { m_overlayHeader = newI; } } m_overlaySelector.setInstances(m_overlayHeader); } } else { m_overlaySelector.clearTableModel(); } } }); basePanel.add(botP, BorderLayout.NORTH); m_configHolder.addTab("Overlay data", null, basePanel, "Specify attributes that are to be considered as \"overlay\" data"); } protected void savePeriodicsToFile() throws IOException { if (m_fileChooser == null) { m_fileChooser = new JFileChooser(new File(System.getProperty("user.home"))); m_fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); FileFilter filter = new ExtensionFileFilter(".periodics", "Time series date-derived " + "periodic attribute definitions (*periodics)"); m_fileChooser.addChoosableFileFilter(filter); } int result = m_fileChooser.showSaveDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File saveFile = m_fileChooser.getSelectedFile(); if (saveFile.toString().indexOf(".periodics") < 0) { saveFile = new File(saveFile.toString() + ".periodics"); } PrintWriter br = new PrintWriter(new BufferedWriter(new FileWriter(saveFile))); br.print("time-series-periodics\n"); int[] selected = m_dateDerivedPeriodicSelector.getSelectedAttributes(); if (m_dateDerivedPeriodicsHeader != null) { for (int i = 0; i < selected.length; i++) { int s = selected[i]; String name = m_dateDerivedPeriodicsHeader.attribute(s).name(); if (s < NUM_PREDEFINED_PERIODICS) { br.print("*pre-defined*:" + name + "\n"); } else { // remove the "c_" name = name.replaceFirst("c_", ""); ArrayList<CustomPeriodicTest> selectedP = m_customPeriodics.get(name); br.print("*custom*:" + name + "\n"); for (int j = 0; j < selectedP.size(); j++) { br.print(selectedP.get(j).toString() + "\n"); } } } } br.flush(); br.close(); } } protected void loadPeriodicsFromFile() throws IOException { if (m_fileChooser == null) { m_fileChooser = new JFileChooser(new File(System.getProperty("user.home"))); m_fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); FileFilter filter = new ExtensionFileFilter(".periodics", "Time series date-derived " + "periodic attribute definitions (*periodics)"); m_fileChooser.addChoosableFileFilter(filter); } int result = m_fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File loadFile = m_fileChooser.getSelectedFile(); BufferedReader br = new BufferedReader(new FileReader(loadFile)); String identifierLine = br.readLine(); boolean ok = false; if (identifierLine != null) { if (identifierLine.equalsIgnoreCase("time-series-periodics")) { ok = true; } } if (!ok) { JOptionPane.showConfirmDialog(this, "\"" + loadFile.toString() + "\" does not" + "\nappear to be a periodic attribute definition file", "Unrecognised file type", JOptionPane.ERROR_MESSAGE); return; } String line = null; boolean withinCustom = false; m_customPeriodics.clear(); List<String> predefined = new ArrayList<String>(); ArrayList<CustomPeriodicTest> testList = null; String currentCustomName = null; while ((line = br.readLine()) != null) { if (line.startsWith("*pre-defined*:")) { if (withinCustom) { // finish custom m_customPeriodics.put(currentCustomName, testList); } withinCustom = false; line = line.substring(line.indexOf(":") + 1, line.length()).trim(); // process predefined type predefined.add(line); } else if (line.startsWith("*custom*:")) { if (withinCustom) { // finish custom m_customPeriodics.put(currentCustomName, testList); } // start new custom testList = new ArrayList<CustomPeriodicTest>(); currentCustomName = line.substring(line.indexOf(":") + 1, line.length()).trim(); withinCustom = true; } else if (withinCustom) { // process custom part try { CustomPeriodicTest t = new CustomPeriodicTest(line); testList.add(t); } catch (IllegalArgumentException ex) { ex.printStackTrace(); JOptionPane.showConfirmDialog(this, "A problem occurred while parsing\n" + "the following custom periodic test:\n" + line, "Error parsing custom test", JOptionPane.ERROR_MESSAGE); return; } } } br.close(); // check for last custom (if exists) if (testList != null && testList.size() > 0) { m_customPeriodics.put(currentCustomName, testList); } m_dateDerivedPeriodicSelector.clearTableModel(); Instances insts = createDateDerivedPeriodicList(); m_dateDerivedPeriodicSelector.setInstances(insts); m_dateDerivedPeriodicsHeader = insts; boolean[] selected = new boolean[insts.numAttributes()]; for (int i = 0; i < insts.numAttributes(); i++) { if (i < NUM_PREDEFINED_PERIODICS) { switch (i) { case 0: if (predefined.contains("AM")) { selected[i] = true; } break; case 1: if (predefined.contains("DayOfWeek")) { selected[i] = true; } break; case 2: if (predefined.contains("DayOfMonth")) { selected[i] = true; } break; case 3: if (predefined.contains("NumDaysInMonth")) { selected[i] = true; } break; case 4: if (predefined.contains("Weekend")) { selected[i] = true; } break; case 5: if (predefined.contains("Month")) { selected[i] = true; } break; case 6: if (predefined.contains("Quarter")) { selected[i] = true; } break; } } else { selected[i] = true; } } try { m_dateDerivedPeriodicSelector.setSelectedAttributes(selected); } catch (Exception ex) { ex.printStackTrace(); } } } protected void layoutDateDerivedPeriodicPanel() { JPanel basePanel = new JPanel(); basePanel.setLayout(new BorderLayout()); JPanel temp = new JPanel(); temp.setLayout(new BorderLayout()); //temp JPanel checkHolder = new JPanel(); checkHolder.setLayout(new BorderLayout()); checkHolder.add(m_customizeDateDerivedPeriodics, BorderLayout.EAST); JPanel editButsP = new JPanel(); editButsP.setLayout(new GridLayout(1,5)); editButsP.add(m_addCustomPeriodicBut); editButsP.add(m_deleteCustomPeriodicBut); editButsP.add(m_editCustomPeriodicBut); editButsP.add(m_savePeriodicBut); editButsP.add(m_loadPeriodicBut); m_loadPeriodicBut.setEnabled(false); m_savePeriodicBut.setEnabled(false); m_savePeriodicBut.setToolTipText("Save checked date-derived " + "periodic definitions to a file"); m_savePeriodicBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { savePeriodicsToFile(); } catch (IOException ex) { ex.printStackTrace(); } } }); m_loadPeriodicBut.setToolTipText("Load pre-saved date-derived periodic " + "definitions from a file"); m_loadPeriodicBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { loadPeriodicsFromFile(); } catch (IOException ex) { ex.printStackTrace(); } } }); checkHolder.add(editButsP, BorderLayout.WEST); m_editCustomPeriodicBut.setEnabled(false); m_editCustomPeriodicBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int selectedRow = m_dateDerivedPeriodicSelector.getTable().getSelectedRow(); if (selectedRow > NUM_PREDEFINED_PERIODICS - 1) { String fieldName = m_dateDerivedPeriodicsHeader.attribute(selectedRow).name(); // need to trim off the "c_" fieldName = fieldName.replaceFirst("c_", ""); ArrayList<CustomPeriodicTest> toEdit = m_customPeriodics.get(fieldName); if (toEdit == null) { System.err.println("Oh oh, couldn't find " + fieldName + " to edit!"); } else { // now make a copy of it try { SerializedObject so = new SerializedObject(toEdit); toEdit = (ArrayList<CustomPeriodicTest>)so.getObject(); String newFieldName = displayAddEditDialog(toEdit, fieldName); if (newFieldName.length() == 0) { // cancel selected so do nothing } else if (!newFieldName.equals(fieldName)) { // user has changed the field name. Delete the old one first m_customPeriodics.remove(fieldName); m_customPeriodics.put(newFieldName, toEdit); // now have to refresh the list in order to show the new name // what's been selected so far? int[] selected = m_dateDerivedPeriodicSelector.getSelectedAttributes(); Instances insts = createDateDerivedPeriodicList(); m_dateDerivedPeriodicSelector.setInstances(insts); m_dateDerivedPeriodicsHeader = insts; boolean[] newSelected = new boolean[insts.numAttributes()]; for (int i = 0; i < selected.length; i++) { newSelected[selected[i]] = true; } try { m_dateDerivedPeriodicSelector.setSelectedAttributes(newSelected); } catch (Exception ex) { ex.printStackTrace(); } } else { // name unchanged, so can just update the map m_customPeriodics.put(fieldName, toEdit); } } catch (Exception e1) { e1.printStackTrace(); } } } } }); m_deleteCustomPeriodicBut.setEnabled(false); m_deleteCustomPeriodicBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int selectedRow = m_dateDerivedPeriodicSelector.getTable().getSelectedRow(); if (selectedRow > NUM_PREDEFINED_PERIODICS - 1) { String fieldName = m_dateDerivedPeriodicsHeader.attribute(selectedRow).name(); // need to trim off the "c_" fieldName = fieldName.replaceFirst("c_", ""); // Confirm delete int result = JOptionPane.showConfirmDialog(AdvancedConfigPanel.this, "Delete field " + fieldName + "?", "Delete custom periodic field", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.NO_OPTION) { return; } m_customPeriodics.remove(fieldName); // what's been selected so far? int[] selected = m_dateDerivedPeriodicSelector.getSelectedAttributes(); Instances oldList = m_dateDerivedPeriodicsHeader; // now need to rebuild the list Instances insts = createDateDerivedPeriodicList(); m_dateDerivedPeriodicSelector.setInstances(insts); m_dateDerivedPeriodicsHeader = insts; // make sure that selected stuff stays selected boolean[] newSelected = new boolean[insts.numAttributes()]; for (int i = 0; i < selected.length; i++) { Attribute toFind = oldList.attribute(selected[i]); Attribute toSet = insts.attribute(toFind.name()); if (toSet != null) { newSelected[toSet.index()] = true; } } try { m_dateDerivedPeriodicSelector.setSelectedAttributes(newSelected); } catch (Exception e1) { e1.printStackTrace(); } } } }); m_addCustomPeriodicBut.setEnabled(false); m_addCustomPeriodicBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ArrayList<CustomPeriodicTest> testList = new ArrayList<CustomPeriodicTest>(); String fieldName = displayAddEditDialog(testList, null); if (fieldName.length() == 0) { // basically do nothing } else { // Add this new one to the Map m_customPeriodics.put(fieldName, testList); // what's been selected so far? int[] selected = m_dateDerivedPeriodicSelector.getSelectedAttributes(); Instances insts = createDateDerivedPeriodicList(); m_dateDerivedPeriodicSelector.setInstances(insts); m_dateDerivedPeriodicsHeader = insts; boolean[] newSelected = new boolean[insts.numAttributes()]; for (int i = 0; i < selected.length; i++) { newSelected[selected[i]] = true; } // select the newly created field newSelected[newSelected.length - 1] = true; try { m_dateDerivedPeriodicSelector.setSelectedAttributes(newSelected); } catch (Exception e1) { e1.printStackTrace(); } } } }); temp.add(checkHolder, BorderLayout.NORTH); temp.add(m_dateDerivedPeriodicSelector, BorderLayout.CENTER); m_dateDerivedPeriodicSelector.setPreferredScrollableViewportSize(new Dimension(250,80)); JPanel botP = new JPanel(); botP.setLayout(new BorderLayout()); botP.setBorder(BorderFactory. createTitledBorder("Date-derived periodic creation")); botP.add(temp, BorderLayout.CENTER); JPanel primaryPeriodicP = new JPanel(); primaryPeriodicP.setLayout(new BorderLayout()); //primaryPeriodicP primaryPeriodicP.add(m_primaryPeriodicCombo, BorderLayout.NORTH); JPanel topP = new JPanel(); topP.setLayout(new BorderLayout()); topP.setBorder(BorderFactory.createTitledBorder("Periodic attribute")); topP.add(primaryPeriodicP, BorderLayout.EAST); JPanel temp2 = new JPanel(); temp2.setLayout(new BorderLayout()); temp2.add(topP, BorderLayout.EAST); temp2.add(botP, BorderLayout.CENTER); // basePanel.add(primaryPeriodicP, BorderLayout.EAST); basePanel.add(temp2, BorderLayout.NORTH); m_customizeDateDerivedPeriodics.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_instances != null && m_customizeDateDerivedPeriodics.isSelected()) { String selectedTimeStamp = m_simpleConfig.m_timeStampCombo.getSelectedItem().toString(); Attribute timeStampAtt = m_instances.attribute(selectedTimeStamp); if (timeStampAtt != null && timeStampAtt.isDate()) { if (m_dateDerivedPeriodicSelector.getSelectionModel() != null) { Instances insts = createDateDerivedPeriodicList(); m_dateDerivedPeriodicSelector.setInstances(insts); m_dateDerivedPeriodicsHeader = insts; m_addCustomPeriodicBut.setEnabled(true); m_savePeriodicBut.setEnabled(true); m_loadPeriodicBut.setEnabled(true); m_dateDerivedPeriodicSelector.getSelectionModel(). addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { if (m_dateDerivedPeriodicSelector.getTable(). getSelectedRow() > NUM_PREDEFINED_PERIODICS - 1) { m_editCustomPeriodicBut.setEnabled(true); m_deleteCustomPeriodicBut.setEnabled(true); } else { m_editCustomPeriodicBut.setEnabled(false); m_deleteCustomPeriodicBut.setEnabled(false); } } } }); } } } else { m_addCustomPeriodicBut.setEnabled(false); m_loadPeriodicBut.setEnabled(false); m_savePeriodicBut.setEnabled(false); } } }); updatePrimaryPeriodic(); //holder.add(basePanel, BorderLayout.WEST); m_configHolder.addTab("Periodic attributes", null, basePanel, "Specify/clustomize periodic attributes"); updateDateDerivedPanel(); } /** * Layout the learner panel */ protected void layoutLearnerPanel() { JPanel basePanel = new JPanel(); basePanel.setLayout(new BorderLayout()); basePanel.setBorder(BorderFactory. createTitledBorder("Base learner configuration")); m_baseLearnerEditor.setClassType(Classifier.class); m_baseLearnerEditor.setValue(new weka.classifiers.functions.SMOreg()); Capabilities capabilities = new Capabilities(null); capabilities.disableAll(); capabilities.enable(Capability.NOMINAL_ATTRIBUTES); capabilities.enable(Capability.NUMERIC_ATTRIBUTES); capabilities.enable(Capability.NUMERIC_CLASS); capabilities.enableAllAttributeDependencies(); capabilities.enableAllClassDependencies(); m_baseLearnerEditor.setCapabilitiesFilter(capabilities); basePanel.add(m_baseLearnerPanel, BorderLayout.NORTH); //add(basePanel, BorderLayout.NORTH); m_configHolder.addTab("Base learner", null, basePanel, "Base learner configuration"); } /** * Layout the lag panel */ protected void layoutLagPanel() { // lag stuff JPanel lagPanel = new JPanel(); lagPanel.setLayout(new GridLayout(1,2)); //lagPanel.setBorder(BorderFactory.createTitledBorder("Lag creation")); SpinnerNumberModel snm = new SpinnerNumberModel(); snm.setValue(1); snm.setMinimum(1); m_minLagSpinner = new JSpinner(snm); Dimension spinD = m_minLagSpinner.getPreferredSize(); spinD = new Dimension((int)(spinD.getWidth() * 1.5), (int)spinD.getHeight()); m_minLagSpinner.setPreferredSize(spinD); JPanel temp1 = new JPanel(); temp1.setBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0)); temp1.setLayout(new BorderLayout()); final JLabel minLagLab = new JLabel("Minimum lag", JLabel.RIGHT); temp1.add(minLagLab, BorderLayout.CENTER); temp1.add(m_minLagSpinner, BorderLayout.EAST); JPanel spinnerHolder = new JPanel(); spinnerHolder.setLayout(new BorderLayout()); spinnerHolder.setBorder(BorderFactory.createTitledBorder("Lag length")); JPanel vH = new JPanel(); vH.setLayout(new BorderLayout()); JPanel varianceHolder = new JPanel(); varianceHolder.setLayout(new BorderLayout()); varianceHolder.add(m_adjustForVarianceCheckBox, BorderLayout.EAST); m_adjustForVarianceCheckBox.setSelected(false); vH.add(varianceHolder, BorderLayout.NORTH); JPanel checkHolder = new JPanel(); checkHolder.setLayout(new BorderLayout()); checkHolder.add(m_useCustomLags, BorderLayout.EAST); vH.add(checkHolder, BorderLayout.SOUTH); spinnerHolder.add(vH, BorderLayout.NORTH); spinnerHolder.add(temp1, BorderLayout.CENTER); snm = new SpinnerNumberModel(); snm.setValue(12); snm.setMinimum(1); m_maxLagSpinner = new JSpinner(snm); m_maxLagSpinner.setPreferredSize(spinD); JPanel temp2 = new JPanel(); temp2.setLayout(new BorderLayout()); temp2.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0)); final JLabel maxLagLab = new JLabel("Maximum lag", JLabel.RIGHT); temp2.add(maxLagLab, BorderLayout.CENTER); temp2.add(m_maxLagSpinner, BorderLayout.EAST); final JLabel fineTuneLab = new JLabel("Fine tune lag selection", JLabel.RIGHT); JPanel fPanel = new JPanel(); fPanel.setLayout(new BorderLayout()); fPanel.add(temp2, BorderLayout.NORTH); JPanel fineHolder = new JPanel(); fineHolder.setLayout(new BorderLayout()); fineHolder.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0)); fineHolder.add(fineTuneLab, BorderLayout.CENTER); fineHolder.add(m_fineTuneLagsField, BorderLayout.EAST); m_fineTuneLagsField.setPreferredSize(spinD); fineTuneLab.setEnabled(false); fineTuneLab.setToolTipText("Specify ranges to fine tune " + "lags within minimum and maximum (e.g. 2,3,6-8)"); m_fineTuneLagsField.setEnabled(false); m_fineTuneLagsField.setToolTipText("Specify ranges to fine tune " + "lags within minimum and maximum (e.g. 2,3,6-8)"); fPanel.add(fineHolder,BorderLayout.SOUTH); spinnerHolder.add(fPanel, BorderLayout.SOUTH); m_useCustomLags.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean enabled = m_useCustomLags.isSelected(); m_minLagSpinner.setEnabled(enabled); m_maxLagSpinner.setEnabled(enabled); minLagLab.setEnabled(enabled); maxLagLab.setEnabled(enabled); fineTuneLab.setEnabled(enabled); m_fineTuneLagsField.setEnabled(enabled); m_averageLongLags.setEnabled(enabled); if (!enabled) { m_averageLongLags.setSelected(false); } /*m_averageLagsAfter.setEnabled(enabled); m_numConsecutiveToAverage.setEnabled(enabled); */ } }); snm = new SpinnerNumberModel(); snm.setValue(2); snm.setMinimum(1); m_averageLagsAfter = new JSpinner(snm); m_averageLagsAfter.setPreferredSize(spinD); snm = new SpinnerNumberModel(); snm.setValue(2); snm.setMinimum(2); m_numConsecutiveToAverage = new JSpinner(snm); m_numConsecutiveToAverage.setPreferredSize(spinD); JPanel averageLagHolder = new JPanel(); averageLagHolder.setBorder(BorderFactory.createTitledBorder("Averaging")); averageLagHolder.setLayout(new BorderLayout()); JPanel avCheckHolder = new JPanel(); avCheckHolder.setLayout(new BorderLayout()); avCheckHolder.add(m_averageLongLags, BorderLayout.EAST); averageLagHolder.add(avCheckHolder, BorderLayout.NORTH); JPanel temp3 = new JPanel(); temp3.setLayout(new BorderLayout()); temp3.setBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0)); final JLabel avLab =new JLabel("Average lags longer than", JLabel.RIGHT); temp3.add(avLab, BorderLayout.CENTER); temp3.add(m_averageLagsAfter, BorderLayout.EAST); JPanel aH = new JPanel(); aH.setLayout(new BorderLayout()); aH.add(temp3, BorderLayout.NORTH); //averageLagHolder.add(temp3, BorderLayout.CENTER); JPanel temp4 = new JPanel(); temp4.setLayout(new BorderLayout()); temp4.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0)); final JLabel numConsLab = new JLabel("# consecutive lags to average", JLabel.RIGHT); temp4.add(numConsLab, BorderLayout.CENTER); temp4.add(m_numConsecutiveToAverage, BorderLayout.EAST); aH.add(temp4, BorderLayout.SOUTH); averageLagHolder.add(aH, BorderLayout.SOUTH); m_useCustomLags.setSelected(false); m_minLagSpinner.setEnabled(false); m_maxLagSpinner.setEnabled(false); minLagLab.setEnabled(false); maxLagLab.setEnabled(false); m_averageLongLags.setEnabled(false); avLab.setEnabled(false); m_averageLagsAfter.setEnabled(false); m_numConsecutiveToAverage.setEnabled(false); numConsLab.setEnabled(false); m_averageLongLags.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_useCustomLags.isSelected()) { boolean enabled = m_averageLongLags.isSelected(); m_averageLagsAfter.setEnabled(enabled); m_numConsecutiveToAverage.setEnabled(enabled); avLab.setEnabled(enabled); numConsLab.setEnabled(enabled); } } }); lagPanel.add(spinnerHolder);//, BorderLayout.CENTER); lagPanel.add(averageLagHolder);//, BorderLayout.EAST); JPanel tempP = new JPanel(); tempP.setLayout(new BorderLayout()); tempP.add(lagPanel, BorderLayout.NORTH); //add(tempP, BorderLayout.CENTER); m_configHolder.addTab("Lag creation", null, tempP, "Customize lagged variables"); } /** * Apply the configuration defined in this panel to the supplied forecaster * * @param forecaster the forecaster to apply the configuration to * @throws Exception if a problem occurs */ public void applyToForecaster(WekaForecaster forecaster) throws Exception { if (forecaster != null) { TSLagMaker lagMaker = forecaster.getTSLagMaker(); // Set variance adjustment lagMaker.setAdjustForVariance(m_adjustForVarianceCheckBox.isSelected()); int minLag = ((SpinnerNumberModel)m_minLagSpinner.getModel()). getNumber().intValue(); int maxLag = ((SpinnerNumberModel)m_maxLagSpinner.getModel()). getNumber().intValue(); if (m_useCustomLags.isSelected()) { // set lag lengths from spinners if (maxLag < minLag) { throw new Exception("Maximum lag value must be greater than or equal to" + " the minimum lag value"); } if (m_instances != null && maxLag > m_instances.numInstances()) { throw new Exception("The maximum lag can't exceed the number instances (" + m_instances.numInstances() + ") in the data!"); } lagMaker.setMinLag(minLag); lagMaker.setMaxLag(maxLag); if (m_fineTuneLagsField.getText() != null && m_fineTuneLagsField.getText().length() > 0) { lagMaker.setLagRange(m_fineTuneLagsField.getText()); } // set up averaging from spinners if (m_averageLongLags.isSelected()) { lagMaker.setAverageConsecutiveLongLags(true); int avLagsAfter = ((SpinnerNumberModel)m_averageLagsAfter.getModel()). getNumber().intValue(); int numToAv = ((SpinnerNumberModel)m_numConsecutiveToAverage.getModel()). getNumber().intValue(); if (avLagsAfter < minLag || avLagsAfter > maxLag) { throw new Exception("Point at which to start lag averaging must " + "lie between the minimum and maximum lag value."); } lagMaker.setAverageLagsAfter(avLagsAfter); lagMaker.setNumConsecutiveLongLagsToAverage(numToAv); } else { lagMaker.setAverageConsecutiveLongLags(false); } } else { lagMaker.setAverageConsecutiveLongLags(false); lagMaker.setLagRange(""); } // date-derived periodic customization if (getCustomizeDateDerivedPeriodics()) { // reset all to false lagMaker.setAddAMIndicator(false); lagMaker.setAddDayOfWeek(false); lagMaker.setAddMonthOfYear(false); lagMaker.setAddQuarterOfYear(false); lagMaker.setAddWeekendIndicator(false); lagMaker.setAddDayOfMonth(false); lagMaker.setAddNumDaysInMonth(false); int[] selected = m_dateDerivedPeriodicSelector.getSelectedAttributes(); if (m_dateDerivedPeriodicsHeader != null) { Map<String, ArrayList<CustomPeriodicTest>> custom = new HashMap<String, ArrayList<CustomPeriodicTest>>(); for (int i = 0; i < selected.length; i++) { int s = selected[i]; String name = m_dateDerivedPeriodicsHeader.attribute(s).name(); if (s < NUM_PREDEFINED_PERIODICS) { if (name.equals("AM")) { lagMaker.setAddAMIndicator(true); } if (name.equals("DayOfWeek")) { lagMaker.setAddDayOfWeek(true); } if (name.equals("DayOfMonth")) { lagMaker.setAddDayOfMonth(true); } if (name.equals("NumDaysInMonth")) { lagMaker.setAddNumDaysInMonth(true); } if (name.equals("Weekend")) { lagMaker.setAddWeekendIndicator(true); } if (name.equals("Month")) { lagMaker.setAddMonthOfYear(true); } if (name.equals("Quarter")) { lagMaker.setAddQuarterOfYear(true); } } else { // remove the "c_" name = name.replaceFirst("c_", ""); ArrayList<CustomPeriodicTest> selectedP = m_customPeriodics.get(name); custom.put(name, selectedP); } } lagMaker.clearCustomPeriodics(); if (custom.size() > 0) { lagMaker.setCustomPeriodics(custom); } } } // non-date primary periodic attribute String ppfn = m_primaryPeriodicCombo.getSelectedItem().toString(); if (!ppfn.equals("<None>")) { lagMaker.setPrimaryPeriodicFieldName(ppfn); } else { lagMaker.setPrimaryPeriodicFieldName(""); } if (m_useOverlayData.isSelected() && m_overlayHeader != null && forecaster instanceof OverlayForecaster) { int[] selected = m_overlaySelector.getSelectedAttributes(); String overlayList = ""; for (int i = 0; i < selected.length; i++) { overlayList += m_overlayHeader.attribute(selected[i]).name() + ","; } if (overlayList.length() > 0) { overlayList = overlayList.substring(0, overlayList.lastIndexOf(',')); ((OverlayForecaster)forecaster).setOverlayFields(overlayList); } else { ((OverlayForecaster)forecaster).setOverlayFields(null); } } else { if (forecaster instanceof OverlayForecaster) { ((OverlayForecaster)forecaster).setOverlayFields(null); } } } } /** * Apply the configuration defined in this panel to the supplied evaluation * object * * @param eval the evaluation object to apply the configuration to * @param forecaster the forecaster in use * @throws Exception if a problem occurs */ public void applyToEvaluation(TSEvaluation eval, WekaForecaster forecaster) throws Exception { // eval on training eval.setEvaluateOnTrainingData(m_trainingCheckBox.isSelected()); if (!eval.getEvaluateOnTrainingData() && !eval.getEvaluateOnTestData()) { // throw new Exception("Must evaluate") } // evaluation modules int[] selected = m_evaluationMetrics.getSelectedAttributes(); if (selected.length == 0) { throw new Exception("Must select at least one evaluation metric."); } List<TSEvalModule> modsList = TSEvalModule.getModuleList(); String modListS = ""; for (int s : selected) { String name = m_evaluationModsHeader.attribute(s).name(); for (TSEvalModule mod : modsList) { if (name.equals(mod.toString())) { modListS += mod.getEvalName() + ","; } } } modListS = modListS.substring(0, modListS.lastIndexOf(',')); eval.setEvaluationModules(modListS); // TODO separate test set } /** * Tests the Weka advanced config panel from the command line. * * @param args must contain the name of an arff file to load. */ public static void main(String[] args) { try { if (args.length == 0) { throw new Exception("supply the name of an arff file"); } Instances i = new Instances(new java.io.BufferedReader( new java.io.FileReader(args[0]))); SimpleConfigPanel scp = new SimpleConfigPanel(null); scp.setInstances(i); AdvancedConfigPanel acp = new AdvancedConfigPanel(scp); //acp.setInstances(i); final javax.swing.JFrame jf = new javax.swing.JFrame("Weka Forecasting"); jf.getContentPane().setLayout(new BorderLayout()); jf.getContentPane().add(acp, BorderLayout.CENTER); jf.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { jf.dispose(); System.exit(0); } }); jf.pack(); jf.setVisible(true); } catch (Exception ex) { ex.printStackTrace(); System.err.println(ex.getMessage()); } } }