/**
* 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.filter;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.annotation.ResourceConsumptionEstimator;
import com.rapidminer.operator.ports.metadata.AttributeMetaData;
import com.rapidminer.operator.ports.metadata.ExampleSetMetaData;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeDouble;
import com.rapidminer.parameter.UndefinedParameterError;
import com.rapidminer.parameter.conditions.EqualTypeCondition;
import com.rapidminer.tools.Ontology;
import com.rapidminer.tools.OperatorResourceConsumptionHandler;
/**
* Replaces positive and negative infinite values in examples by one of the functions
* "none", "zero", "max_byte", "max_int",
* "max_double", and "missing". "none" means, that the value is not
* replaced. The max_xxx functions replace plus infinity by the upper bound and minus infinity by
* the lower bound of the range of the Java type xxx. "missing" means, that the value is
* replaced by nan (not a number), which is internally used to represent missing values. A
* {@link MissingValueReplenishment} operator can be used to replace missing values by average (or
* the mode for nominal attributes), maximum, minimum etc. afterwards.<br/>
* For each attribute, the function can be selected using the parameter list <code>columns</code>.
* If an attribute's name appears in this list as a key, the value is used as the function name. If
* the attribute's name is not in the list, the function specified by the <code>default</code>
* parameter is used.
*
* @author Simon Fischer, Ingo Mierswa
*/
public class InfiniteValueReplenishment extends ValueReplenishment {
public static final String PARAMETER_REPLENISHMENT_VALUE = "replenishment_value";
public static final String PARAMETER_REPLENISHMENT_WHAT = "replenish_what";
private static final int NONE = 0;
private static final int ZERO = 1;
private static final int MAX_BYTE = 2;
private static final int MAX_INT = 3;
private static final int MAX_DOUBLE = 4;
private static final int MISSING = 5;
private static final int VALUE = 6;
private static final String[] REP_NAMES = { "none", "zero", "max_byte", "max_int", "max_double", "missing", "value" };
private static final String[] WHAT_NAMES = { "positive_infinity", "negative_infinity" };
public InfiniteValueReplenishment(OperatorDescription description) {
super(description);
}
@Override
protected Collection<AttributeMetaData> modifyAttributeMetaData(ExampleSetMetaData emd, AttributeMetaData amd)
throws UndefinedParameterError {
return Collections.singletonList(amd);
}
@Override
public double getReplacedValue() {
try {
int chosen = getParameterAsInt(PARAMETER_REPLENISHMENT_WHAT);
if (chosen == 0) {
return Double.POSITIVE_INFINITY;
}
} catch (Exception e) {
}
return Double.NEGATIVE_INFINITY;
}
@Override
protected int[] getFilterValueTypes() {
return new int[] { Ontology.NUMERICAL };
}
@Override
public String[] getFunctionNames() {
return REP_NAMES;
}
@Override
public int getDefaultFunction() {
return MAX_DOUBLE;
}
@Override
public int getDefaultColumnFunction() {
return ZERO;
}
/**
* Replaces the values
*
* @throws UndefinedParameterError
*/
@Override
public double getReplenishmentValue(int functionIndex, ExampleSet exampleSet, Attribute attribute)
throws UndefinedParameterError {
int chosen = getParameterAsInt(PARAMETER_REPLENISHMENT_WHAT);
switch (functionIndex) {
case NONE:
return Double.POSITIVE_INFINITY;
case ZERO:
return 0.0;
case MAX_BYTE:
return (chosen == 0) ? Byte.MAX_VALUE : Byte.MIN_VALUE;
case MAX_INT:
return (chosen == 0) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
case MAX_DOUBLE:
return (chosen == 0) ? Double.MAX_VALUE : -Double.MAX_VALUE;
case MISSING:
return Double.NaN;
case VALUE:
return getParameterAsDouble(PARAMETER_REPLENISHMENT_VALUE);
default:
throw new RuntimeException("Illegal value functionIndex: " + functionIndex);
}
}
@Override
public List<ParameterType> getParameterTypes() {
List<ParameterType> types = super.getParameterTypes();
ParameterType type = new ParameterTypeCategory(PARAMETER_REPLENISHMENT_WHAT,
"Decides if positive or negative infite values will be replaced.", WHAT_NAMES, 0, false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_REPLENISHMENT_VALUE, "This value will be inserted instead of infinity.",
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, true);
type.registerDependencyCondition(new EqualTypeCondition(this, PARAMETER_DEFAULT, getFunctionNames(), true, VALUE));
types.add(type);
return types;
}
@Override
public boolean writesIntoExistingData() {
// the model takes care of materialization
return false;
}
@Override
public ResourceConsumptionEstimator getResourceConsumptionEstimator() {
return OperatorResourceConsumptionHandler.getResourceConsumptionEstimator(getInputPort(),
InfiniteValueReplenishment.class, attributeSelector);
}
}