/*
* 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;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.AttributeRole;
import com.rapidminer.example.Attributes;
import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.table.AttributeFactory;
import com.rapidminer.example.table.DoubleArrayDataRow;
import com.rapidminer.example.table.MemoryExampleTable;
import com.rapidminer.operator.IOObject;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.preprocessing.filter.ChangeAttributeType;
import com.rapidminer.tools.Ontology;
/**
* <p>This operator transposes an example set, i.e. the columns with become the
* new rows and the old rows will become the columns. Hence, this operator
* works very similar to the well know transpose operation for matrices.</p>
*
* <p>If an Id attribute is part of the given example set, the ids will become
* the names of the new attributes. The names of the old attributes will be
* transformed into the id values of a new special Id attribute. Since no
* other "special" examples or data rows exist, all other new
* attributes will be regular after the transformation. You can use
* the {@link ChangeAttributeType} operator in order to change one of
* these into a special type afterwards.</p>
*
* <p>If all old attribute have the same value type, all new attributes
* will have this value type. Otherwise, the new value types will all be
* "nominal" if at least one nominal attribute was part of the
* given example set and "real" if the types contained mixed
* numbers.</p>
*
* <p>This operator produces a copy of the data in the main memory and it
* therefore not suggested to use it on very large data sets.</p>
*
* @author Ingo Mierswa
* @version $Id: ExampleSetTranspose.java,v 1.5 2008/07/07 07:06:42 ingomierswa Exp $
*/
public class ExampleSetTranspose extends Operator {
public ExampleSetTranspose(OperatorDescription description) {
super(description);
}
public IOObject[] apply() throws OperatorException {
ExampleSet exampleSet = getInput(ExampleSet.class);
// determine new value types
int valueType = Ontology.REAL;
Iterator<AttributeRole> a = exampleSet.getAttributes().allAttributeRoles();
while (a.hasNext()) {
AttributeRole attributeRole = a.next();
if ((!attributeRole.isSpecial()) || (!attributeRole.getSpecialName().equals(Attributes.ID_NAME))) {
if (attributeRole.getAttribute().isNominal()) {
valueType = Ontology.NOMINAL;
break;
}
}
}
// create new attributes
List<Attribute> newAttributes = new ArrayList<Attribute>(exampleSet.size());
Attribute newIdAttribute = AttributeFactory.createAttribute(Attributes.ID_NAME, Ontology.NOMINAL);
newAttributes.add(newIdAttribute);
Attribute oldIdAttribute = exampleSet.getAttributes().getId();
if (oldIdAttribute != null) {
for (Example e : exampleSet) {
double idValue = e.getValue(oldIdAttribute);
String attributeName = "att_" + idValue;
if (oldIdAttribute.isNominal()) {
attributeName = oldIdAttribute.getMapping().mapIndex((int)idValue);
}
newAttributes.add(AttributeFactory.createAttribute(attributeName, valueType));
}
} else {
for (int i = 0; i < exampleSet.size(); i++) {
newAttributes.add(AttributeFactory.createAttribute("att_" + (i+1), valueType));
}
}
// create and fill table
MemoryExampleTable table = new MemoryExampleTable(newAttributes);
a = exampleSet.getAttributes().allAttributeRoles();
while (a.hasNext()) {
AttributeRole attributeRole = a.next();
if ((!attributeRole.isSpecial()) || (!attributeRole.getSpecialName().equals(Attributes.ID_NAME))) {
Attribute attribute = attributeRole.getAttribute();
double[] data = new double[exampleSet.size() + 1];
data[0] = newIdAttribute.getMapping().mapString(attribute.getName());
int counter = 1;
for (Example e : exampleSet) {
double currentValue = e.getValue(attribute);
data[counter] = currentValue;
Attribute newAttribute = newAttributes.get(counter);
if (newAttribute.isNominal()) {
if (!Double.isNaN(currentValue)) {
String currentValueString = currentValue + "";
if (attribute.isNominal())
currentValueString = attribute.getMapping().mapIndex((int)currentValue);
data[counter] = newAttribute.getMapping().mapString(currentValueString);
}
}
counter++;
}
table.addDataRow(new DoubleArrayDataRow(data));
}
}
// create and deliver example set
ExampleSet result = table.createExampleSet(null, null, newIdAttribute);
return new IOObject[] { result };
}
public Class<?>[] getInputClasses() {
return new Class[] { ExampleSet.class };
}
public Class<?>[] getOutputClasses() {
return new Class[] { ExampleSet.class };
}
}