/*
* RapidMiner
*
* Copyright (C) 2001-2011 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.features.weighting;
import java.util.List;
import com.rapidminer.example.AttributeWeights;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.learner.CapabilityCheck;
import com.rapidminer.operator.learner.CapabilityProvider;
import com.rapidminer.operator.ports.InputPort;
import com.rapidminer.operator.ports.OutputPort;
import com.rapidminer.operator.ports.metadata.AttributeMetaData;
import com.rapidminer.operator.ports.metadata.CapabilityPrecondition;
import com.rapidminer.operator.ports.metadata.ExampleSetMetaData;
import com.rapidminer.operator.ports.metadata.ExampleSetPassThroughRule;
import com.rapidminer.operator.ports.metadata.GenerateNewMDRule;
import com.rapidminer.operator.ports.metadata.SetRelation;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeBoolean;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.UndefinedParameterError;
import com.rapidminer.parameter.conditions.BooleanParameterCondition;
import com.rapidminer.tools.ParameterService;
import com.rapidminer.tools.Tools;
/**
* This is an abstract superclass for RapidMiner weighting operators. New weighting
* schemes should extend this class to support the same normalization parameter as
* other weighting operators.
*
* @author Helge Homburg
*/
public abstract class AbstractWeighting extends Operator implements CapabilityProvider {
private InputPort exampleSetInput = getInputPorts().createPort("example set");
private OutputPort weightsOutput = getOutputPorts().createPort("weights");
private OutputPort exampleSetOutput = getOutputPorts().createPort("example set");
private static final String[] SORT_DIRECTIONS = new String[] {
"ascending",
"descending"
};
public static final int SORT_ASCENDING = 0;
public static final int SORT_DESCENDING = 1;
/** The parameter name for "Activates the normalization of all weights." */
public static final String PARAMETER_NORMALIZE_WEIGHTS = "normalize_weights";
public static final String PARAMETER_SORT_WEIGHTS = "sort_weights";
public static final String PARAMETER_SORT_DIRECTION = "sort_direction";
public AbstractWeighting(OperatorDescription description) {
super(description);
if (isExampleSetMandatory())
exampleSetInput.addPrecondition(new CapabilityPrecondition(this, exampleSetInput));
getTransformer().addRule(new GenerateNewMDRule(weightsOutput, AttributeWeights.class));
getTransformer().addRule(new ExampleSetPassThroughRule(exampleSetInput, exampleSetOutput, SetRelation.EQUAL) {
@Override
public ExampleSetMetaData modifyExampleSet(ExampleSetMetaData metaData) throws UndefinedParameterError {
boolean normalizedWeights = getParameterAsBoolean(PARAMETER_NORMALIZE_WEIGHTS);
for (AttributeMetaData amd: metaData.getAllAttributes()) {
if (!amd.isSpecial() && amd.isNumerical()) {
if (normalizedWeights)
amd.setValueSetRelation(SetRelation.SUBSET);
else
amd.setValueSetRelation(SetRelation.UNKNOWN);
}
}
return super.modifyExampleSet(metaData);
}
});
}
protected abstract AttributeWeights calculateWeights(ExampleSet exampleSet) throws OperatorException;
/** Helper method for anonymous instances of this class.
*/
public AttributeWeights doWork(ExampleSet exampleSet) throws OperatorException {
exampleSetInput.receive(exampleSet);
// check capabilities and produce errors if they are not fulfilled
CapabilityCheck check = new CapabilityCheck(this, Tools.booleanValue(ParameterService.getParameterValue(PROPERTY_RAPIDMINER_GENERAL_CAPABILITIES_WARN), true) || onlyWarnForNonSufficientCapabilities());
check.checkLearnerCapabilities(this, exampleSet);
doWork();
return weightsOutput.getData();
}
@Override
public void doWork() throws OperatorException {
ExampleSet exampleSet =
isExampleSetMandatory() ? exampleSetInput.getData(ExampleSet.class) : exampleSetInput.<ExampleSet>getDataOrNull();
AttributeWeights weights = calculateWeights(exampleSet);
if (getParameterAsBoolean(PARAMETER_NORMALIZE_WEIGHTS)) {
weights.normalize();
}
if (getParameterAsBoolean(PARAMETER_SORT_WEIGHTS)) {
weights.sort(getParameterAsInt(PARAMETER_SORT_DIRECTION) == SORT_ASCENDING? AttributeWeights.INCREASING: AttributeWeights.DECREASING, AttributeWeights.ORIGINAL_WEIGHTS);
}
exampleSetOutput.deliver(exampleSet);
weightsOutput.deliver(weights);
}
public InputPort getExampleSetInputPort() {
return exampleSetInput;
}
public OutputPort getWeightsOutputPort() {
return weightsOutput;
}
@Override
public List<ParameterType> getParameterTypes() {
List<ParameterType> list = super.getParameterTypes();
list.add(new ParameterTypeBoolean(PARAMETER_NORMALIZE_WEIGHTS, "Activates the normalization of all weights.", true, false));
list.add(new ParameterTypeBoolean(PARAMETER_SORT_WEIGHTS, "If activated the weights will be returned sorted.", true, false));
ParameterType type = new ParameterTypeCategory(PARAMETER_SORT_DIRECTION, "Defines the sorting direction.", SORT_DIRECTIONS, 0);
type.registerDependencyCondition(new BooleanParameterCondition(this, PARAMETER_SORT_WEIGHTS, true, true));
list.add(type);
return list;
}
protected boolean isExampleSetMandatory() {
return true;
}
protected boolean onlyWarnForNonSufficientCapabilities() {
return false;
}
}