meka.filters.unsupervised.attribute.MekaClassAttributes.java Source code

Java tutorial

Introduction

Here is the source code for meka.filters.unsupervised.attribute.MekaClassAttributes.java

Source

/*
 *   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/>.
 */

/**
 * MekaClassAttributes.java
 * Copyright (C) 2012 University of Waikato, Hamilton, New Zealand
 */
package meka.filters.unsupervised.attribute;

import java.util.Enumeration;
import java.util.Vector;

import weka.filters.unsupervised.attribute.Reorder;
import weka.core.Capabilities;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Option;
import weka.core.Range;
import weka.core.RevisionUtils;
import weka.core.Utils;
import weka.core.WekaException;
import weka.filters.SimpleStreamFilter;

/**
 * Reorders attributes for MEKA to use as class attributes.
 * 
 * @author  fracpete (fracpete at waikato dot ac dot nz)
 * @version $Revision: 66 $
 */
public class MekaClassAttributes extends SimpleStreamFilter {

    /** for serialization. */
    private static final long serialVersionUID = 6733841542030233313L;

    /** the range of attributes to use as class attributes. */
    protected Range m_AttributeIndices = new Range("last");

    /** for reordering the attributes. */
    protected Reorder m_Reorder = new Reorder();

    /**
     * Returns a string describing this filter.
     *
     * @return       a description of the filter suitable for
     *          displaying in the explorer/experimenter gui
     */
    public String globalInfo() {
        return "Reorders attributes for MEKA. Attribute range defines the "
                + "attributes to use as class attributes.";
    }

    /**
     * Returns an enumeration describing the available options.
     *
     * @return an enumeration of all the available options.
     */
    public Enumeration listOptions() {
        Vector newVector = new Vector();

        newVector.addElement(new Option(
                "\tSpecify list of columns to use as MEKA class attributes. 'first' and 'last' are valid\n"
                        + "\tindexes. (default: last)",
                "R", 1, "-R <index1,index2-index4,...>"));

        return newVector.elements();
    }

    /**
     * Parses a given list of options.
     *
     * @param options the list of options as an array of strings
     * @throws Exception if an option is not supported
     */
    public void setOptions(String[] options) throws Exception {
        String orderList = Utils.getOption('R', options);
        if (orderList.length() != 0)
            setAttributeIndices(orderList);
        else
            setAttributeIndices("last");

        if (getInputFormat() != null)
            setInputFormat(getInputFormat());
    }

    /**
     * Gets the current settings of the filter.
     *
     * @return an array of strings suitable for passing to setOptions
     */
    public String[] getOptions() {
        String[] options = new String[2];
        int current = 0;

        if (!getAttributeIndices().equals("")) {
            options[current++] = "-R";
            options[current++] = getAttributeIndices();
        }

        while (current < options.length) {
            options[current++] = "";
        }
        return options;
    }

    /**
     * Set which attributes are to be used as MEKA class attributes.
     *
     * @param value a string representing the list of attributes.  Since
     * the string will typically come from a user, attributes are indexed from
     * 1. <br>
     * eg: first-3,5,6-last<br>
     * Note: use this method before you call 
     * <code>setInputFormat(Instances)</code>, since the output format is
     * determined in that method.
     * @throws Exception if an invalid range list is supplied
     */
    public void setAttributeIndices(String value) throws Exception {
        // simple test
        if (value.replaceAll("[afilrst0-9\\-,]*", "").length() != 0)
            throw new IllegalArgumentException("Not a valid range string!");

        m_AttributeIndices.setRanges(value);
    }

    /**
     * Get the current range selection
     *
     * @return a string containing a comma separated list of ranges
     */
    public String getAttributeIndices() {
        return m_AttributeIndices.getRanges();
    }

    /**
     * Returns the tip text for this property
     *
     * @return tip text for this property suitable for
     * displaying in the explorer/experimenter gui
     */
    public String attributeIndicesTipText() {
        return "Specify range of attributes to use as MEKA class attributes."
                + " This is a comma separated list of attribute indices, with"
                + " \"first\" and \"last\" valid values. Specify an inclusive"
                + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
    }

    /** 
     * Returns the Capabilities of this filter.
     *
     * @return            the capabilities of this object
     * @see               Capabilities
     */
    public Capabilities getCapabilities() {
        Capabilities result;

        result = m_Reorder.getCapabilities();
        result.setOwner(this);

        return result;
    }

    /**
     * Determines the output format based on the input format and returns 
     * this. In case the output format cannot be returned immediately, i.e.,
     * hasImmediateOutputFormat() returns false, then this method will called
     * from batchFinished() after the call of preprocess(Instances), in which,
     * e.g., statistics for the actual processing step can be gathered.
     *
     * @param inputFormat     the input format to base the output format on
     * @return                the output format
     * @throws Exception      in case the determination goes wrong
     */
    protected Instances determineOutputFormat(Instances inputFormat) throws Exception {
        int i;
        int[] indices;
        StringBuilder order;
        Instances output;

        m_AttributeIndices.setUpper(inputFormat.numAttributes() - 1);
        order = new StringBuilder();
        indices = m_AttributeIndices.getSelection();
        if (indices.length == 0)
            throw new WekaException("No attributes defined as class attributes!");
        for (i = 0; i < indices.length; i++) {
            if (i > 0)
                order.append(",");
            order.append("" + (indices[i] + 1));
        }
        for (i = 0; i < inputFormat.numAttributes(); i++) {
            if (m_AttributeIndices.isInRange(i))
                continue;
            order.append(",");
            order.append("" + (i + 1));
        }
        m_Reorder.setAttributeIndices(order.toString());
        m_Reorder.setInputFormat(inputFormat);

        output = m_Reorder.getOutputFormat();
        output.setClassIndex(indices.length);
        output.setRelationName("-C " + indices.length);

        return output;
    }

    /**
     * processes the given instance (may change the provided instance) and
     * returns the modified version.
     *
     * @param instance    the instance to process
     * @return            the modified data
     * @throws Exception  in case the processing goes wrong
     */
    protected Instance process(Instance instance) throws Exception {
        m_Reorder.input(instance);
        m_Reorder.batchFinished();
        return m_Reorder.output();
    }

    public String getRevision() {
        return RevisionUtils.extract("$Revision: 66 $");
    }

    /**
     * runs the filter with the given arguments.
     *
     * @param args      the commandline arguments
     */
    public static void main(String[] args) {
        runFilter(new MekaClassAttributes(), args);
    }
}