/* * 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.set; import com.rapidminer.example.Attribute; import com.rapidminer.example.Example; import com.rapidminer.example.ExampleSet; import com.rapidminer.tools.Tools; /** * The condition is fulfilled if an attribute has a value equal to, not equal to, * less than, ... a given value. * * @author Ingo Mierswa * @version $Id: AttributeValueFilterSingleCondition.java,v 1.9 2008/08/28 18:54:07 ingomierswa Exp $ */ public class AttributeValueFilterSingleCondition implements Condition { private static final long serialVersionUID = 1537763901048986863L; private static final String[] COMPARISON_TYPES = { "<=", ">=", "!=", "<>", "=", "<", ">" }; public static final int LEQ = 0; public static final int GEQ = 1; public static final int NEQ1 = 2; public static final int NEQ2 = 3; public static final int EQUALS = 4; public static final int LESS = 5; public static final int GREATER = 6; private int comparisonType = EQUALS; private Attribute attribute; private double numericalValue; private String nominalValue; /** * Creates a new AttributeValueFilter. If attribute is not nominal, value * must be a number. */ public AttributeValueFilterSingleCondition(Attribute attribute, int comparisonType, String value) { this.attribute = attribute; this.comparisonType = comparisonType; setValue(value); } /** * Constructs an AttributeValueFilter for a given {@link ExampleSet} from a * parameter string * * @param parameterString * Must be of the form attribute R value, where R is one out of =, * !=, <&, >, <=, and >=. */ public AttributeValueFilterSingleCondition(ExampleSet exampleSet, String parameterString) { if ((parameterString == null) || (parameterString.length() == 0)) throw new IllegalArgumentException("Parameter string must not be empty!"); int compIndex = -1; for (comparisonType = 0; comparisonType < COMPARISON_TYPES.length; comparisonType++) { compIndex = parameterString.indexOf(COMPARISON_TYPES[comparisonType]); if (compIndex != -1) break; } if (compIndex == -1) throw new IllegalArgumentException("Parameter string must have the form 'attribute {=|<|>|<=|>=|!=} value'"); String attName = parameterString.substring(0, compIndex).trim(); String valueStr = parameterString.substring(compIndex + COMPARISON_TYPES[comparisonType].length()).trim(); if ((attName.length() == 0) || (valueStr.length() == 0)) throw new IllegalArgumentException("Parameter string must have the form 'attribute {=|<|>|<=|>=|!=} value'"); this.attribute = exampleSet.getAttributes().get(attName); if (this.attribute == null) { throw new IllegalArgumentException("Unknown attribute: '" + attName + "'"); } setValue(valueStr); } private void setValue(String value) { if (attribute.isNominal()) { if ((comparisonType != EQUALS) && (comparisonType != NEQ1 && comparisonType != NEQ2)) throw new IllegalArgumentException("For nominal attributes only '=' and '!=' or '<>' is allowed!"); this.nominalValue = value; } else { try { this.numericalValue = Double.parseDouble(value); } catch (NumberFormatException e) { throw new IllegalArgumentException("Value for attribute '" + attribute.getName() + "' must be numerical!"); } } } /** * Since the condition cannot be altered after creation we can just return * the condition object itself. * * @deprecated Conditions should not be able to be changed dynamically and hence there is no need for a copy */ @Deprecated public Condition duplicate() { return this; } public String toString() { return attribute.getName() + " " + COMPARISON_TYPES[comparisonType] + " " + (attribute.isNominal() ? nominalValue : "" + numericalValue); } /** Returns true if the condition is fulfilled for the given example. */ public boolean conditionOk(Example e) { if (attribute.isNominal()) { switch (comparisonType) { case NEQ1: case NEQ2: return !e.getNominalValue(attribute).matches(nominalValue); case EQUALS: return e.getNominalValue(attribute).matches(nominalValue); default: return false; } } else { switch (comparisonType) { case LEQ: return Tools.isLessEqual(e.getNumericalValue(attribute), numericalValue); case GEQ: return Tools.isGreaterEqual(e.getNumericalValue(attribute), numericalValue); case NEQ1: case NEQ2: return Tools.isNotEqual(e.getNumericalValue(attribute), numericalValue); case EQUALS: return Tools.isEqual(e.getNumericalValue(attribute), numericalValue); case LESS: return Tools.isLess(e.getNumericalValue(attribute), numericalValue); case GREATER: return Tools.isGreater(e.getNumericalValue(attribute), numericalValue); default: return false; } } } }