/* * 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.example.table; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import com.rapidminer.example.Attribute; import com.rapidminer.example.ConstructionDescription; import com.rapidminer.tools.Ontology; import de.tud.inf.example.table.ComplexCompositeAttribute; import de.tud.inf.example.table.ConstantArrayAttribute; import de.tud.inf.example.table.DataMapAttribute; import de.tud.inf.example.table.GaussAttribute; import de.tud.inf.example.table.HistogramAttribute; import de.tud.inf.example.table.MapAttribute; import de.tud.inf.example.table.MatrixAttribute; import de.tud.inf.example.table.PointListAttribute; import de.tud.inf.example.table.RelationalAttribute; import de.tud.inf.example.table.TensorAttribute; import de.tud.inf.example.table.UniformAttribute; /** * This class is used to create and clone attributes. It should be used to * create attributes instead of directly creating them by using constructors. * Additionally, it provides some helper methods for attribute creation purposes * (name creation, block numbers,...). * * @author Ingo Mierswa * @version $Id: AttributeFactory.java,v 2.12 2006/03/21 15:35:39 ingomierswa * Exp $ */ public class AttributeFactory { /** The prefix of the name of generated attributes. */ private static final String GENSYM_PREFIX = "gensym"; /** * The current highest id counters for generated attribute names. The counter will be increased each time an * attribute name is generated more than once. */ private static Map<String,AtomicInteger> nameCounters = new HashMap<String,AtomicInteger>(); static { resetNameCounters(); } /** Creates a simple single attribute depending on the given value type. */ public static Attribute createAttribute(String name, int valueType) { String attributeName = (name != null) ? name : createName(); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.DATE_TIME)) { return new DateAttribute(attributeName, valueType); } else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.BINOMINAL)) { return new BinominalAttribute(attributeName); } else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.NOMINAL)) { return new PolynominalAttribute(attributeName, valueType); } else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.NUMERICAL)) { return new NumericalAttribute(attributeName, valueType); } else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.RELATIONAL)) { return new RelationalAttribute(attributeName, valueType); } else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.MAP)) return new MapAttribute(attributeName, valueType,""); else if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.DATA_MAP)) return new DataMapAttribute(attributeName, valueType,""); else { throw new RuntimeException("AttributeFactory: cannot create attribute with value type '" + Ontology.ATTRIBUTE_VALUE_TYPE.mapIndex(valueType) + "' (" + valueType + ")!"); } } /** * create Attribute, where an additional information (hint) is necessary, e.g. {@link com.rapidminer.operator.visualization.ProcessLogOperator} * @param name * @param valueType * @param hint * @return */ public static Attribute createAttribute(String name, int valueType, String hint){ String attributeName = (name != null) ? name : createName(); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.ARRAY)) return new ConstantArrayAttribute(attributeName, valueType,hint); else throw new RuntimeException("AttributeFactory: cannot create attribute with value type '" + Ontology.ATTRIBUTE_VALUE_TYPE.mapIndex(valueType) + "' (" + valueType + ")!"); } public static Attribute createCompositeAttribute(String name, int valueType, List<Attribute> innerAttributes, List<Attribute> parameters, String hint){ String attributeName = (name != null) ? name : createName(); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.UNIFORM)) return new UniformAttribute(attributeName,valueType,innerAttributes,parameters,hint); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.GAUSS)) return new GaussAttribute(attributeName,valueType,innerAttributes,parameters,hint); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.HISTOGRAM)) return new HistogramAttribute(attributeName,valueType,innerAttributes,parameters,hint); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.COMPLEX_VALUE)) return new ComplexCompositeAttribute(attributeName,valueType,innerAttributes,parameters,hint); else { throw new RuntimeException("AttributeFactory: cannot create attribute with value type '" + Ontology.ATTRIBUTE_VALUE_TYPE.mapIndex(valueType) + "' (" + valueType + ")!"); } } /** * those attribute types just have one inner relational attribute, and cannot be parameterized for each row, but for the complete dataset * @param name * @param valueType * @param innerAttribute * @param hint * @return */ public static Attribute createProxyAttribute(String name, int valueType, RelationalAttribute innerAttribute, String hint){ String attributeName = (name != null) ? name : createName(); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.MATRIX)) return new MatrixAttribute(attributeName,valueType,innerAttribute,hint); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.TENSOR)) return new TensorAttribute(attributeName,valueType,innerAttribute,hint); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.POINT_LIST)) return new PointListAttribute(attributeName,valueType,innerAttribute,hint); //since there are no parameter attributes, ArrayAttribute must be a constant one if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.ARRAY)) return new ConstantArrayAttribute(attributeName,valueType,innerAttribute,hint); if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.DATA_MAP)){ //if attribute, which stores keys of this map is nominal, set correct valueType if(innerAttribute.getInnerAttributeAt(0).isNominal() ) return new DataMapAttribute(attributeName,Ontology.DATA_MAP_STRING,innerAttribute,hint); return new DataMapAttribute(attributeName,valueType,innerAttribute,hint); } else { throw new RuntimeException("AttributeFactory: cannot create attribute with value type '" + Ontology.ATTRIBUTE_VALUE_TYPE.mapIndex(valueType) + "' (" + valueType + ")!"); } } /** * create complex proxy attribute, which has additional parameter attributes (e.g. map) */ public static Attribute createProxyAttribute(String name, int valueType, RelationalAttribute innerAttribute, List<Attribute> parameters, String symbol,String hint){ String attributeName = (name != null) ? name : createName(); //if attribute, which stores z values of this map is nominal, set correct valueType if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.MAP)){ if(innerAttribute.getInnerAttributeAt(0).isNominal() ) return new MapAttribute(attributeName,Ontology.MAP_STRING,innerAttribute,parameters,hint); return new MapAttribute(attributeName,valueType,innerAttribute,parameters,hint); } /* //create parameterized array attribute if there are parameter attributes, else create constant array attribute if (Ontology.ATTRIBUTE_VALUE_TYPE.isA(valueType, Ontology.ARRAY) && parameters.size() > 0) return new ArrayAttribute(attributeName,valueType,innerAttribute,hint,parameters.get(0),parameters.get(1)); */ else return createProxyAttribute(name,valueType,innerAttribute,hint); } /** * Creates a simple single attribute depending on the given value type. The * name is randomly created. This attribute can also be used for generators * to define their desired input attributes for compatibility checks. */ public static Attribute createAttribute(int valueType) { return createAttribute(createName(), valueType); } /** Creates a single numerical constructed attribute. */ public static Attribute createAttribute(String functionName, ConstructionDescription[] arguments) { return createAttribute(Ontology.NUMERICAL, Ontology.SINGLE_VALUE, functionName, arguments); } /** Creates a simple attribute depending on the given value type. */ public static Attribute createAttribute(int valueType, int blockType, String functionName, ConstructionDescription[] arguments) { Attribute attribute = createAttribute(valueType); attribute.setBlockType(blockType); attribute.getConstruction().setFunction(functionName); attribute.getConstruction().setArguments(arguments); return attribute; } /** Creates a simple attribute depending on the given value type. */ public static Attribute createAttribute(String name, int valueType, int blockType) { Attribute attribute = createAttribute(name, valueType); attribute.setBlockType(blockType); return attribute; } // ================================================================================ /** * Simple clone factory method for attributes. Invokes * {@link #createAttribute(Attribute att, String name)} with name = null. */ public static Attribute createAttribute(Attribute attribute) { return createAttribute(attribute, null); } /** * Simple clone factory method for attributes. Returns the clone of the * given attribute and sets the function name to the given one if not null. * In this case the attribute is used as an argument of returned attribute. * This method might be usefull for example to create a prediction attribute * with the same properties as the original label attribute. */ public static Attribute createAttribute(Attribute attribute, String functionName) { Attribute result = (Attribute) attribute.clone(); if (functionName == null) { result.setName(attribute.getName()); } else { result.setName(functionName + "(" + attribute.getName() + ")"); result.getConstruction().setFunction(functionName); result.getConstruction().setArguments(new ConstructionDescription[] { attribute.getConstruction() }); } return result; } // ================================================================================ // changes the value type of the given attribute // ================================================================================ /** * Changes the value type of the given attribute and returns a new attribute * with the same properties but the new value type. Since values within examples are * not altered it is not suggested to use this method to change attributes within an * exampleset in use. Operators should create a new attribute to ensure parallel executability. */ public static Attribute changeValueType(Attribute attribute, int valueType) { Attribute result = createAttribute(attribute.getName(), valueType); if (attribute.isNominal() && result.isNominal()) result.setMapping(attribute.getMapping()); result.setTableIndex(attribute.getTableIndex()); return result; } // ================================================================================ // helper methods // ================================================================================ /** Resets the counters for the generated attribute names. */ public static void resetNameCounters() { nameCounters.clear(); } /** Creates a new unsused attribute name. */ public static String createName() { return createName(GENSYM_PREFIX); } /** Creates a new unsused attribute name with a given prefix. */ public static String createName(String prefix) { AtomicInteger counter = nameCounters.get(prefix); if (counter == null) { nameCounters.put(prefix, new AtomicInteger(1)); return prefix; } else { return prefix + counter.getAndIncrement(); } } }