/*
* RapidMiner
*
* Copyright (C) 2001-2008 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.operator.preprocessing.filter;
import java.util.LinkedList;
import java.util.List;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.table.AttributeFactory;
import com.rapidminer.operator.IOObject;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeBoolean;
import com.rapidminer.parameter.ParameterTypeInt;
import com.rapidminer.parameter.ParameterTypeString;
import com.rapidminer.tools.Ontology;
/**
* <p>
* This operator performs several transformations which could be performed
* by basic RapidMiner operators but lead to complex operator chains. Therefore,
* this operator can be used as a shortcut.
* </p>
*
* <p>
* The basic idea is to apply this operator on a windowed data set like those
* create be the (Multivariate)Series2WindowExamples operators. Please note that
* only series data sets where the series was represented by the examples (rows)
* are supported by this operator due to the naming conventions of the
* resulting attributes.
* </p>
*
* <p>
* This operator performs three basic tasks. First, it removed all attributes lying
* between the time point zero (attribute name ending "-0") and the time
* point before horizon values. Second, it transforms the corresponding time point zero
* of the specified label stem to the actual label. Last, it re-represents all values
* relative to the last known time value for each original dimension including the
* label value.
* </p>
*
* @author Ingo Mierswa
* @version $Id: WindowExamples2ModellingData.java,v 1.1 2008/09/08 18:53:49 ingomierswa Exp $
*/
public class WindowExamples2ModellingData extends Operator {
public static final String PARAMETER_LABEL_NAME_STEM = "label_name_stem";
public static final String PARAMETER_HORIZON = "horizon";
public static final String PARAMETER_RELATIVE_TRANSFORMATION = "relative_transformation";
public WindowExamples2ModellingData(OperatorDescription description) {
super(description);
}
public IOObject[] apply() throws OperatorException {
ExampleSet exampleSet = getInput(ExampleSet.class);
String labelName = getParameterAsString(PARAMETER_LABEL_NAME_STEM);
int horizon = getParameterAsInt(PARAMETER_HORIZON);
// TODO: check if appropriate label is there
// TODO: check if window width is large enough
// collect base names and attributes to remove, find label
Attribute labelAttribute = null;
List<String> baseNames = new LinkedList<String>();
List<Attribute> toRemove = new LinkedList<Attribute>();
int windowWidth = 0;
for (Attribute attribute : exampleSet.getAttributes()) {
if (attribute.getName().endsWith("-0")) {
String baseName = attribute.getName().substring(0, attribute.getName().lastIndexOf("-"));
baseNames.add(baseName);
if (attribute.getName().startsWith(labelName)) {
labelAttribute = attribute;
}
}
int index = Integer.valueOf(attribute.getName().substring(attribute.getName().lastIndexOf("-") + 1));
windowWidth = Math.max(windowWidth, index);
if ((index >= 0) && (index < horizon)) {
toRemove.add(attribute);
}
}
// remove horizon attributes
for (Attribute attribute : toRemove) {
exampleSet.getAttributes().remove(attribute);
}
// set label
exampleSet.getAttributes().setLabel(labelAttribute);
// transform all values relative to last known label attribute value and create base value column
if (getParameterAsBoolean(PARAMETER_RELATIVE_TRANSFORMATION)) {
if (labelAttribute.isNumerical()) {
Attribute baseValueAttribute = AttributeFactory.createAttribute("base_value", Ontology.REAL);
exampleSet.getExampleTable().addAttribute(baseValueAttribute);
exampleSet.getAttributes().setSpecialAttribute(baseValueAttribute, "base_value");
for (Example example : exampleSet) {
// handle label
String lastKnownLabelName = labelName + "-" + horizon;
Attribute lastKnownLabelAttribute = exampleSet.getAttributes().get(lastKnownLabelName);
double baseLabelValue = example.getValue(lastKnownLabelAttribute);
example.setValue(baseValueAttribute, baseLabelValue);
for (String baseName : baseNames) {
String lastKnownBaseName = baseName + "-" + horizon;
Attribute lastKnownBaseAttribute = exampleSet.getAttributes().get(lastKnownBaseName);
double baseAttributeValue = example.getValue(lastKnownBaseAttribute);
for (int w = horizon; w <= windowWidth; w++) {
String currentName = baseName + "-" + w;
Attribute currentAttribute = exampleSet.getAttributes().get(currentName);
double currentValue = example.getValue(currentAttribute);
example.setValue(currentAttribute, currentValue - baseAttributeValue);
}
}
example.setValue(labelAttribute, example.getValue(labelAttribute) - baseLabelValue);
}
}
}
return new IOObject[] { exampleSet };
}
public Class<?>[] getInputClasses() {
return new Class[] { ExampleSet.class };
}
public Class<?>[] getOutputClasses() {
return new Class[] { ExampleSet.class };
}
public List<ParameterType> getParameterTypes() {
List<ParameterType> types = super.getParameterTypes();
types.add(new ParameterTypeString(PARAMETER_LABEL_NAME_STEM, "The name stem of the label attribute.", false));
types.add(new ParameterTypeInt(PARAMETER_HORIZON, "The horizon for the prediction.", 1, Integer.MAX_VALUE, 1));
types.add(new ParameterTypeBoolean(PARAMETER_RELATIVE_TRANSFORMATION, "Indicates if a relative transformation of value should be performed", true));
return types;
}
}