/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.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 com.rapidminer.example.Attribute; import com.rapidminer.example.AttributeRole; import com.rapidminer.example.Example; import com.rapidminer.example.ExampleSet; import com.rapidminer.example.set.ConditionCreationException; import com.rapidminer.example.set.NonSpecialAttributesExampleSet; import com.rapidminer.operator.OperatorChain; import com.rapidminer.operator.OperatorDescription; import com.rapidminer.operator.OperatorException; import com.rapidminer.operator.ProcessSetupError.Severity; import com.rapidminer.operator.SimpleProcessSetupError; import com.rapidminer.operator.UserError; import com.rapidminer.operator.annotation.ResourceConsumptionEstimator; import com.rapidminer.operator.ports.InputPort; import com.rapidminer.operator.ports.OutputPort; import com.rapidminer.operator.ports.PortPairExtender; import com.rapidminer.operator.ports.metadata.AttributeMetaData; import com.rapidminer.operator.ports.metadata.AttributeSubsetPassThroughRule; import com.rapidminer.operator.ports.metadata.ExampleSetMetaData; import com.rapidminer.operator.ports.metadata.ExampleSetPassThroughRule; import com.rapidminer.operator.ports.metadata.MetaData; import com.rapidminer.operator.ports.metadata.MetaDataInfo; import com.rapidminer.operator.ports.metadata.SetRelation; import com.rapidminer.operator.ports.metadata.SimpleMetaDataError; import com.rapidminer.operator.ports.metadata.SubprocessTransformRule; import com.rapidminer.operator.tools.AttributeSubsetSelector; import com.rapidminer.parameter.ParameterType; import com.rapidminer.parameter.ParameterTypeBoolean; import com.rapidminer.parameter.ParameterTypeCategory; import com.rapidminer.parameter.UndefinedParameterError; import com.rapidminer.tools.OperatorResourceConsumptionHandler; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * <p> * This operator can be used to select one attribute (or a subset) by defining a regular expression * for the attribute name and applies its inner operators to the resulting subset. Please note that * this operator will also use special attributes which makes it necessary for all preprocessing * steps which should be performed on special attributes (and are normally not performed on special * attributes). * </p> * * <p> * This operator is also able to deliver the additional results of the inner operator if desired. * </p> * * <p> * Afterwards, the remaining original attributes are added to the resulting example set if the * parameter "keep_subset_only" is set to false (default). * </p> * * <p> * Please note that this operator is very powerful and can be used to create new preprocessing * schemes by combining it with other preprocessing operators. However, there are two major * restrictions (among some others): first, since the inner result will be combined with the rest of * the input example set, the number of examples (data points) is not allowed to be changed inside * of the subset preprocessing. Second, attribute role changes will not be delivered to the outside * since internally all special attributes will be changed to regular for the inner operators and * role changes can afterwards not be delivered. * </p> * * @author Ingo Mierswa, Shevek */ public class AttributeSubsetPreprocessing extends OperatorChain { /** * The parameter name for "Indicates if the additional results (other than example set) of * the inner operator should also be returned." */ public static final String PARAMETER_DELIVER_INNER_RESULTS = "deliver_inner_results"; /** * The parameter name for "Indicates if the attributes which did not match the regular * expression should be removed by this operator." */ public static final String PARAMETER_KEEP_SUBSET_ONLY = "keep_subset_only"; /** The parameter name for "Indicates how to handle with doubling of Attributenames */ public static final String PARAMETER_ROLE_CONFLICT_HANDLING = "role_conflict_handling"; private static final String[] HANDLE_ROLE_CONFLICT_MODES = { "error", "keep new", "keep original" }; private static final int HANDLE_ROLE_CONFLICT_ERROR = 0; private static final int HANDLE_ROLE_CONFLICT_KEEP_NEW = 1; private static final int HANDLE_ROLE_CONFLICT_KEEP_ORIGINAL = 2; public static final String PARAMETER_NAME_CONFLICT_HANDLING = "name_conflict_handling"; private static final String[] HANDLE_NAME_CONFLICT_MODES = { "error", "keep new", "keep original" }; private static final int HANDLE_NAME_CONFLICT_ERROR = 0; private static final int HANDLE_NAME_CONFLICT_KEEP_NEW = 1; private static final int HANDLE_NAME_CONFLICT_KEEP_ORIGINAL = 2; public static final String PARAMETER_REMOVE_ROLES = "remove_roles"; private final InputPort exampleSetInput = getInputPorts().createPort("example set", ExampleSet.class); private final OutputPort innerExampleSetSource = getSubprocess(0).getInnerSources().createPort("exampleSet"); private final InputPort innerExampleSetSink = getSubprocess(0).getInnerSinks().createPort("example set", ExampleSet.class); private final OutputPort exampleSetOutput = getOutputPorts().createPort("example set"); private final PortPairExtender innerResultPorts = new PortPairExtender("through", getSubprocess(0).getInnerSinks(), getOutputPorts()); private final AttributeSubsetSelector attributeSelector = new AttributeSubsetSelector(this, exampleSetInput); public AttributeSubsetPreprocessing(OperatorDescription description) { super(description, "Subset Process"); getTransformer().addRule(new AttributeSubsetPassThroughRule(exampleSetInput, innerExampleSetSource, this, false) { @Override public ExampleSetMetaData modifyExampleSet(ExampleSetMetaData metaData) { // checking if condition creation works try { AttributeSubsetSelector.createCondition( operator.getParameterAsString(AttributeSubsetSelector.PARAMETER_FILTER_TYPE), operator); } catch (UndefinedParameterError e) { // a standard error is already thrown } catch (ConditionCreationException e) { try { operator.addError(new SimpleProcessSetupError(Severity.ERROR, operator.getPortOwner(), "attribute_filter_condition_error", operator .getParameterAsString(AttributeSubsetSelector.PARAMETER_FILTER_TYPE))); } catch (UndefinedParameterError e1) { // a standard error is already thrown } } ExampleSetMetaData result; if (!AttributeSubsetPreprocessing.this.isRemoveRolesSet()) { List<AttributeMetaData> specialAttributes = this.seperateSpecialAttributeMetaData(metaData); result = selector.getMetaDataSubset(metaData, keepSpecialIfNotIncluded); this.restoreSpecialRoles(specialAttributes, result); } else { result = selector.getMetaDataSubset(metaData, keepSpecialIfNotIncluded); } return result; } /** * Separates all AttributeMetaData-Objects with a special role * * @param metaData * ExampleSetMetaData to separate from * @return a List with all AttributeMetaData with a special role */ private List<AttributeMetaData> seperateSpecialAttributeMetaData(ExampleSetMetaData metaData) { ArrayList<AttributeMetaData> specialStuff = new ArrayList<AttributeMetaData>(); for (AttributeMetaData att : metaData.getAllAttributes()) { if (att.isSpecial()) { specialStuff.add(att); } } return specialStuff; } /** * changes the role of the AttributeAttribute in exempleSet(with the same name as a * Attribute in specialAttributes) to the role of the AttributeMetaData in * specialAttributes * * @param specialAttributes * list of AttributeMetaData with special roles * @param exampleSet * ExampleSetMetaData with will be modified */ private void restoreSpecialRoles(List<AttributeMetaData> specialAttributes, ExampleSetMetaData exampleSet) { for (AttributeMetaData specialAttribute : specialAttributes) { AttributeMetaData attributeToChange = exampleSet.getAttributeByName(specialAttribute.getName()); if (attributeToChange != null) { attributeToChange.setRole(specialAttribute.getRole()); } } } }); getTransformer().addRule(new SubprocessTransformRule(getSubprocess(0))); getTransformer().addRule(new ExampleSetPassThroughRule(innerExampleSetSink, exampleSetOutput, SetRelation.UNKNOWN) { @Override public ExampleSetMetaData modifyExampleSet(ExampleSetMetaData inputMetaData) { if (getParameterAsBoolean(PARAMETER_KEEP_SUBSET_ONLY)) { return inputMetaData; } else { MetaData metaData = exampleSetInput.getMetaData(); if (metaData instanceof ExampleSetMetaData) { inputMetaData = (ExampleSetMetaData) metaData; ExampleSetMetaData subsetAmd = attributeSelector.getMetaDataSubset(inputMetaData, false); // restore special Attributes roles if wanted if (!getParameterAsBoolean(PARAMETER_REMOVE_ROLES)) { for (AttributeMetaData attribute : subsetAmd.getAllAttributes()) { AttributeMetaData inputAttribute = inputMetaData.getAttributeByName(attribute.getName()); if (inputAttribute.isSpecial()) { attribute.setRole(inputAttribute.getRole()); } } } // storing unused attributes List<AttributeMetaData> unusedAttributes = new LinkedList<AttributeMetaData>(); Iterator<AttributeMetaData> iterator = inputMetaData.getAllAttributes().iterator(); while (iterator.hasNext()) { AttributeMetaData amd = iterator.next(); if (!(subsetAmd.containsAttributeName(amd.getName()) == MetaDataInfo.YES)) { unusedAttributes.add(amd); } } // retrieving result if (innerExampleSetSink.getMetaData() instanceof ExampleSetMetaData) { ExampleSetMetaData resultMetaData = (ExampleSetMetaData) innerExampleSetSink.getMetaData() .clone(); // merge and add unused completely Iterator<AttributeMetaData> iter = unusedAttributes.iterator(); int nameConflict = 0; int roleConflict = 0; try { nameConflict = getParameterAsInt(PARAMETER_NAME_CONFLICT_HANDLING); } catch (UndefinedParameterError e) { } try { roleConflict = getParameterAsInt(PARAMETER_ROLE_CONFLICT_HANDLING); } catch (UndefinedParameterError e) { } while (iter.hasNext()) { AttributeMetaData unusedControl = iter.next(); if (unusedControl.getRole() != null && resultMetaData.getSpecial(unusedControl.getRole()) != null) { // use-cases switch (roleConflict) { case HANDLE_ROLE_CONFLICT_ERROR: innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.new_special_role_exist", new Object[] { unusedControl.getRole(), resultMetaData.getSpecial(unusedControl.getRole()).getName() })); break; case HANDLE_ROLE_CONFLICT_KEEP_ORIGINAL: // remove special attribute AttributeMetaData toRemove = resultMetaData.getSpecial(unusedControl.getRole()); resultMetaData.removeAttribute(toRemove); // throw error if name of original attribute exists at // another point in the resultSet if (resultMetaData.getAttributeByName(unusedControl.getName()) != null) { innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.role_and_name_conflict", new Object[] { unusedControl.getName() })); } else { // insert the new one resultMetaData.addAttribute(unusedControl); } break; case HANDLE_ROLE_CONFLICT_KEEP_NEW: // throw error if the name of the special attribute // exists already, else we don't do anything String SpecialResultName = resultMetaData.getSpecial(unusedControl.getRole()) .getName(); if (!(unusedControl.getName().equals(SpecialResultName)) && inputMetaData.getAttributeByName(SpecialResultName) != null) { // throw error because is case isn't defined innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.role_and_name_conflict", new Object[] { SpecialResultName })); } break; default: // don't do anything, we keep the new one break; } } else { // test for name conflict if (resultMetaData.getAttributeByName(unusedControl.getName()) != null) { if (unusedControl.getRole() != null) { innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.role_and_name_conflict", new Object[] { unusedControl.getName() })); } else { // we have a regular attribute switch (nameConflict) { case HANDLE_NAME_CONFLICT_ERROR: innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.new_attribute_exist", new Object[] { unusedControl.getName() })); break; case HANDLE_NAME_CONFLICT_KEEP_ORIGINAL: // tests whether a attribute with special role // and same name exists AttributeMetaData toRemove = resultMetaData .getAttributeByName(unusedControl.getName()); if (toRemove.isSpecial()) { innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.role_and_name_conflict", new Object[] { unusedControl.getName() })); } else { // act as defined resultMetaData.removeAttribute(toRemove); resultMetaData.addAttribute(unusedControl); } break; case HANDLE_NAME_CONFLICT_KEEP_NEW: // throws error if the attribute with this name // isn't regular an could be removed later in // this // loop AttributeMetaData toKeep = resultMetaData .getAttributeByName(unusedControl.getName()); if (toKeep.isSpecial()) { innerExampleSetSink.addError(new SimpleMetaDataError(Severity.ERROR, innerExampleSetSink, "work_on_subset.role_and_name_conflict", new Object[] { unusedControl.getName() })); } default: // don't do anything, we keep the new one break; } } } else { // there is no conflict for the attribute resultMetaData.addAttribute(unusedControl); }// end if } }// end while return resultMetaData; } } } return inputMetaData; } }); getTransformer().addRule(innerResultPorts.makePassThroughRule()); innerResultPorts.start(); } @Override public void doWork() throws OperatorException { ExampleSet inputSet = exampleSetInput.getData(ExampleSet.class); ExampleSet workingExampleSet = (ExampleSet) inputSet.clone(); Set<Attribute> selectedAttributes = attributeSelector.getAttributeSubset(workingExampleSet, false); List<Attribute> unusedAttributes = new LinkedList<Attribute>(); Iterator<Attribute> iterator = workingExampleSet.getAttributes().allAttributes(); while (iterator.hasNext()) { Attribute attribute = iterator.next(); if (!selectedAttributes.contains(attribute)) { unusedAttributes.add(attribute); iterator.remove(); } } if (getParameterAsBoolean(PARAMETER_REMOVE_ROLES)) { // converting special to normal workingExampleSet = NonSpecialAttributesExampleSet.create(workingExampleSet); } // perform inner operators innerExampleSetSource.deliver(workingExampleSet); getSubprocess(0).execute(); // retrieve transformed example set ExampleSet resultSet = innerExampleSetSink.getData(ExampleSet.class); // add old attributes if desired if (!getParameterAsBoolean(PARAMETER_KEEP_SUBSET_ONLY)) { if (resultSet.size() != inputSet.size()) { throw new UserError(this, 127, "changing the size of the example set is not allowed if the non-processed attributes should be kept."); } mergeSets(resultSet, inputSet, unusedAttributes, resultSet.getExampleTable().equals(inputSet.getExampleTable()), getParameterAsInt(PARAMETER_ROLE_CONFLICT_HANDLING), getParameterAsInt(PARAMETER_NAME_CONFLICT_HANDLING)); } // add all other results if desired innerResultPorts.passDataThrough(); // deliver example set exampleSetOutput.deliver(resultSet); } /** * * @param resultSet * = ExampleSet which will be returned * @param inputSet * = original ExampleSet * @param unusedAttributes * = list of unused Attributes of the original ExampleSet * @param identicalExampleTables * = boolean Value which indicates whether the ExampleSets are the same * @param roleConflictHandling * = integer Value for Role Conflict Handling * @param nameConflictHandling * = integer Value for Name Conflict Handling * @throws UserError */ private void mergeSets(ExampleSet resultSet, ExampleSet inputSet, List<Attribute> unusedAttributes, boolean identicalExampleTables, int roleConflictHandling, int nameConflictHandling) throws UserError { // Check whether the underlying example table has been change if (identicalExampleTables) { // if Attribute names are duplicated it throws an Exception or decide whether the new or // old Attribute should be kept for (Attribute attribute : unusedAttributes) { AttributeRole role = inputSet.getAttributes().getRole(attribute); if (resultSet.getAttributes().getSpecial(role.getSpecialName()) != null) { switch (roleConflictHandling) { case HANDLE_ROLE_CONFLICT_ERROR: throw new UserError(this, "attribute_subset_preprocessing.role_conflict", role.getAttribute() .getName(), resultSet.getAttributes().getSpecial(role.getSpecialName()).getName()); case HANDLE_ROLE_CONFLICT_KEEP_ORIGINAL: // remove special attribute resultSet.getAttributes().remove(attribute); // throw error if name of original attribute exists at another point in // the resultSet if (resultSet.getAttributes().get(attribute.getName()) != null) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", role .getAttribute().getName()); } // insert the new one resultSet.getAttributes().add(role); break; case HANDLE_ROLE_CONFLICT_KEEP_NEW: // throw error if the name of the special attribute exists already, else // we don't do anything String SpecialResultName = resultSet.getAttributes().getSpecial(role.getSpecialName()).getName(); if (inputSet.getAttributes().get(SpecialResultName) != null && !(attribute.getName().equals(SpecialResultName))) { // throw error because is case isn't defined throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", attribute.getName()); } break; default: // don't do anything, we keep the new one break; } } else { // we have a regular attribute or the special attribute isn't part of the result // set until now if (resultSet.getAttributes().get(attribute.getName()) != null) { if (role.isSpecial()) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", attribute.getName()); } // we have a regular attribute switch (nameConflictHandling) { case HANDLE_NAME_CONFLICT_ERROR: throw new UserError(this, "attribute_subset_preprocessing.name_conflict", role .getAttribute().getName()); case HANDLE_NAME_CONFLICT_KEEP_ORIGINAL: // tests whether a attribute with special role and same name exists AttributeRole control = resultSet.getAttributes().getRole(attribute.getName()); if (control.isSpecial()) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", attribute.getName()); } resultSet.getAttributes().remove(attribute); resultSet.getAttributes().add(role); break; case HANDLE_NAME_CONFLICT_KEEP_NEW: AttributeRole Keep = resultSet.getAttributes().getRole(attribute.getName()); if (Keep.isSpecial()) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", attribute.getName()); } default: // don't do anything, we keep the new one break; } } else { // there is no conflict for the attribute resultSet.getAttributes().add(role); } } } } else { // we have two different ExampleSets logWarning("Underlying example table has changed: data copy into new table is necessary in order to keep non-processed attributes."); for (Attribute oldAttribute : unusedAttributes) { AttributeRole oldRole = inputSet.getAttributes().getRole(oldAttribute); if (resultSet.getAttributes().getSpecial(oldRole.getSpecialName()) != null) { switch (roleConflictHandling) { case HANDLE_ROLE_CONFLICT_ERROR: String targetRole = oldRole.getSpecialName(); throw new UserError(this, "attribute_subset_preprocessing.role_conflict", new Object[] { targetRole, resultSet.getAttributes().getSpecial(targetRole).getName() }); case HANDLE_ROLE_CONFLICT_KEEP_ORIGINAL: // remove the special attribute in resultSet and copy the original to // the resulSet resultSet.getAttributes().remove(oldAttribute); // throw error if name of original attribute exists at another point in // the resultSet if (resultSet.getAttributes().get(oldAttribute.getName()) != null) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", oldAttribute.getName()); } // create and add copy of unused attributes from input set Attribute newAttribute = (Attribute) oldAttribute.clone(); resultSet.getExampleTable().addAttribute(newAttribute); AttributeRole newRole = new AttributeRole(newAttribute); if (oldRole.isSpecial()) { newRole.setSpecial(oldRole.getSpecialName()); } // add to result set resultSet.getAttributes().add(newRole); // copy data for the new attribute Iterator<Example> oldIterator = inputSet.iterator(); Iterator<Example> newIterator = resultSet.iterator(); while (oldIterator.hasNext()) { Example oldExample = oldIterator.next(); Example newExample = newIterator.next(); newExample.setValue(newAttribute, oldExample.getValue(oldAttribute)); } break; case HANDLE_ROLE_CONFLICT_KEEP_NEW: // if a name-conflict with other attributes exists we throw an error String SpecialResultName = resultSet.getAttributes().getSpecial(oldRole.getSpecialName()) .getName(); if (inputSet.getAttributes().get(SpecialResultName) != null && !(oldAttribute.getName().equals(SpecialResultName))) { // throw error because this case is not defined throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", oldAttribute.getName()); } break; default: // don't do anything, we keep the new one break; } } else { if (resultSet.getAttributes().get(oldAttribute.getName()) != null) { // we have a regular attribute or the special attribute isn't part of the // result set until now if (oldRole.isSpecial()) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", oldAttribute.getName()); } // we have a regular attribute switch (nameConflictHandling) { case HANDLE_NAME_CONFLICT_ERROR: throw new UserError(this, "attribute_subset_preprocessing.name_conflict", oldAttribute.getName()); case HANDLE_NAME_CONFLICT_KEEP_ORIGINAL: // tests whether a attribute with special role and same name exists AttributeRole control = resultSet.getAttributes().getRole(oldAttribute.getName()); if (control.isSpecial()) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", oldAttribute.getName()); } // remove the attribute in result and copy the original to the // resulSet resultSet.getAttributes().remove(oldAttribute); // create and add copy of unused attributes from input set Attribute newAttribute = (Attribute) oldAttribute.clone(); resultSet.getExampleTable().addAttribute(newAttribute); AttributeRole newRole = new AttributeRole(newAttribute); if (oldRole.isSpecial()) { newRole.setSpecial(oldRole.getSpecialName()); } // add to result set resultSet.getAttributes().add(newRole); // copy data for the new attribute Iterator<Example> oldIterator = inputSet.iterator(); Iterator<Example> newIterator = resultSet.iterator(); while (oldIterator.hasNext()) { Example oldExample = oldIterator.next(); Example newExample = newIterator.next(); newExample.setValue(newAttribute, oldExample.getValue(oldAttribute)); } break; case HANDLE_NAME_CONFLICT_KEEP_NEW: AttributeRole toKeep = resultSet.getAttributes().getRole(oldAttribute.getName()); if (toKeep.isSpecial()) { throw new UserError(this, "attribute_subset_preprocessing.role_name_conflict", oldAttribute.getName()); } default: // don't do anything, we keep the new one break; } } else { // there is no conflict of name or role // create and add copy of unused attributes from input set Attribute newAttribute = (Attribute) oldAttribute.clone(); resultSet.getExampleTable().addAttribute(newAttribute); AttributeRole newRole = new AttributeRole(newAttribute); if (oldRole.isSpecial()) { newRole.setSpecial(oldRole.getSpecialName()); } // add to result set resultSet.getAttributes().add(newRole); // copy data for the new attribute Iterator<Example> oldIterator = inputSet.iterator(); Iterator<Example> newIterator = resultSet.iterator(); while (oldIterator.hasNext()) { Example oldExample = oldIterator.next(); Example newExample = newIterator.next(); newExample.setValue(newAttribute, oldExample.getValue(oldAttribute)); }// end while }// end else } } } } @Override public List<ParameterType> getParameterTypes() { List<ParameterType> types = super.getParameterTypes(); types.addAll(attributeSelector.getParameterTypes()); ParameterType type = new ParameterTypeCategory(PARAMETER_NAME_CONFLICT_HANDLING, "Decides how to deal with duplicate attribute names.", HANDLE_NAME_CONFLICT_MODES, 0); type.setExpert(false); types.add(type); type = new ParameterTypeCategory(PARAMETER_ROLE_CONFLICT_HANDLING, "Decides how to deal with duplicate attribute roles.", HANDLE_ROLE_CONFLICT_MODES, 0); type.setExpert(false); types.add(type); types.add(new ParameterTypeBoolean( PARAMETER_KEEP_SUBSET_ONLY, "Indicates if the attributes which did not match the regular expression should be removed by this operator.", false)); types.add(new ParameterTypeBoolean( PARAMETER_DELIVER_INNER_RESULTS, "Indicates if the additional results (other than example set) of the inner operator should also be returned.", false)); types.add(new ParameterTypeBoolean( PARAMETER_REMOVE_ROLES, "Indicates whether the role of the attributes in the subset will be removed by entering the Operator or not.", false)); return types; } @Override public ResourceConsumptionEstimator getResourceConsumptionEstimator() { return OperatorResourceConsumptionHandler.getResourceConsumptionEstimator(getInputPorts().getPortByIndex(0), AttributeSubsetPreprocessing.class, attributeSelector); } private boolean isRemoveRolesSet() { return getParameterAsBoolean(PARAMETER_REMOVE_ROLES); } }