/*
* 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.filter.attributes;
import java.util.ArrayList;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
import com.rapidminer.example.set.ConditionCreationException;
/**
* This class implements a condition for the AttributeFilter operator.
* It provides the possibility to check if all values of a numerical attribute
* match a condition. This conditions might be specified by != or <>, =, <, <=, >, >=
* followed by a value. For example like this: "> 6.5" would keep all attributes having only values
* greater 6.5.
* This single conditions might be combined by || or && but not mixed. Example: "> 6.5 && < 11" would keep
* all attributes containing only values between 6.5 and 11.
*
* @author Sebastian Land, Ingo Mierswa
* @version $Id: NumericValueAttributeFilter.java,v 1.6 2008/07/19 16:31:17 ingomierswa Exp $
*/
public class NumericValueAttributeFilter implements AttributeFilterCondition {
private ArrayList<Condition> conditions;
private boolean keep = true;
private boolean invert;
private boolean conjunctiveMode;
private static class Condition {
private int condition;
private double value;
public Condition(String condition, String value) {
this.value = Double.parseDouble(value);
if (condition.equals("<>") || condition.equals("!=")) {
this.condition = 1;
} else if (condition.equals("<=")) {
this.condition = 2;
} else if (condition.equals("<")) {
this.condition = 3;
} else if (condition.equals(">=")) {
this.condition = 4;
} else if (condition.equals(">")) {
this.condition = 5;
} else if (condition.equals("=")) {
this.condition = 0;
}
}
public boolean check(double value) {
if (Double.isNaN(value))
return true;
switch (condition) {
case 0: return (value == this.value);
case 1: return (value != this.value);
case 2: return (value <= this.value);
case 3: return (value < this.value);
case 4: return (value >= this.value);
case 5: return (value > this.value);
}
return false;
}
}
/** Initializes the check for the scan. */
public void initScanCheck() {
this.keep = true;
}
public boolean check(Attribute attribute, Example example) {
if (attribute.isNumerical()) {
boolean exampleResult = false;
double checkValue = example.getValue(attribute);
if (conjunctiveMode) {
exampleResult = true;
for(Condition condition : conditions) {
exampleResult = exampleResult && condition.check(checkValue);
}
} else {
exampleResult = false;
for (Condition condition : conditions) {
exampleResult = exampleResult || condition.check(checkValue);
}
}
keep = keep && exampleResult;
}
return (invert ^ !keep) ^ !attribute.isNumerical();
}
public boolean beforeScanCheck(Attribute attribute, String parameter, boolean invert) throws ConditionCreationException {
if ((parameter == null) || (parameter.length() == 0))
throw new ConditionCreationException("The condition for numerical values needs a parameter string.");
this.invert = invert;
// testing if not allowed combination of and and or
if (parameter.contains("||") && parameter.contains("&&")) {
throw new ConditionCreationException("|| and && not allowed in one condition");
}
this.conjunctiveMode = parameter.contains("&&");
conditions = new ArrayList<Condition>();
for (String conditionString: parameter.split("[|&]{2}")) {
String[] parts = conditionString.trim().split("\\s+");
if (parts.length != 2) {
throw new ConditionCreationException("number of condition arguments not correct");
} else {
conditions.add(new Condition(parts[0], parts[1]));
}
}
return false;
}
public boolean isNeedingScan() {
return true;
}
}