/**
* 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.example.set;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.AttributeRole;
import com.rapidminer.example.Attributes;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.UserError;
import com.rapidminer.tools.Ontology;
/**
* This class provides global utility methods for regular operations on ExampleSets or their
* components.
*
* @author Dominik Halfkann
*/
public class ExampleSetUtilities {
/**
* This {@link Comparator} compares {@link AttributeRole}s according to their Role. It can be
* used to sort the (special) Attributes of an {@link ExampleSet}.
*
* It enforces the following order for Attributes: ID -> Label -> Prediction -> Confidence ->
* Cluster -> Weight -> Other Special Attributes -> Other Regular Attributes
*/
public static final Comparator<AttributeRole> SPECIAL_ATTRIBUTES_ROLE_COMPARATOR = new Comparator<AttributeRole>() {
private List<String> priorityList = Arrays.asList(new String[] { Attributes.ID_NAME, Attributes.LABEL_NAME,
Attributes.PREDICTION_NAME, Attributes.CONFIDENCE_NAME, Attributes.CLUSTER_NAME, Attributes.WEIGHT_NAME });
@Override
public int compare(AttributeRole a1, AttributeRole a2) {
// the lower the priority, the earlier the attribute is being sorted
// special attributes should come before regular attributes
int priorityAttribute1 = a1.isSpecial() ? 1000 : 2000;
int priorityAttribute2 = a2.isSpecial() ? 1000 : 2000;
// if the attribute role is in the priority list, use special priority
if (a1.isSpecial() && priorityList.contains(a1.getSpecialName())) {
priorityAttribute1 = priorityList.indexOf(a1.getSpecialName());
}
if (a2.isSpecial() && priorityList.contains(a2.getSpecialName())) {
priorityAttribute2 = priorityList.indexOf(a2.getSpecialName());
}
// special priority for roles that start with "confidence_"
if (a1.isSpecial() && a1.getSpecialName().startsWith(Attributes.CONFIDENCE_NAME + "_")) {
priorityAttribute1 = priorityList.indexOf(Attributes.CONFIDENCE_NAME);
}
if (a2.isSpecial() && a2.getSpecialName().startsWith(Attributes.CONFIDENCE_NAME + "_")) {
priorityAttribute2 = priorityList.indexOf(Attributes.CONFIDENCE_NAME);
}
return priorityAttribute1 - priorityAttribute2;
}
};
/** Determines how to compare the sets of Attributes. */
public static enum SetsCompareOption {
/** Both sets of Attributes must be the same. */
EQUAL,
/** The second set of Attributes must be a subset of the first one. */
ALLOW_SUBSET,
/** The second set of Attributes must be a superset of the first one. */
ALLOW_SUPERSET,
/** Just compare matching Attributes from both sets (intersection). */
USE_INTERSECTION
}
/** Determines how to compare the matching Attributes regarding their types. */
public static enum TypesCompareOption {
/**
* An Attribute from the second set must be of the same type as the corresponding Attribute
* from the first set.
*/
EQUAL,
/**
* An Attribute from the second set must be a subtype of the corresponding Attribute from
* the first set.
*/
ALLOW_SUBTYPES,
/**
* An Attribute from the second set must be a supertype of the corresponding Attribute from
* the first set.
*/
ALLOW_SUPERTYPES,
/**
* An Attribute from the second set must have the same parent as the corresponding Attribute
* from the first set.
*/
ALLOW_SAME_PARENTS,
/** ignores different Types of the Attributes */
DONT_CARE
}
/**
* Check if two sets of Attributes are matching. Throws an {@link UserError} if they are not
* equal with regard to the specified {@link SetsCompareOption} and {@link TypesCompareOption}.
*/
public static void checkAttributesMatching(Operator op, Attributes originalAttributes, Attributes comparedAttributes,
SetsCompareOption compareSets, TypesCompareOption compareTypes) throws UserError {
for (Attribute originalAttribute : originalAttributes) {
if (comparedAttributes.contains(originalAttribute)) {
Attribute comparedAttribute = comparedAttributes.get(originalAttribute.getName());
int originalValueType = originalAttribute.getValueType();
int comparedValueType = comparedAttribute.getValueType();
if (originalValueType != comparedValueType) {
Ontology valueTypes = Ontology.ATTRIBUTE_VALUE_TYPE;
if (compareTypes == TypesCompareOption.ALLOW_SUBTYPES) {
if (!valueTypes.isA(comparedValueType, originalValueType)) {
throw new UserError(op, 964, comparedAttribute.getName(),
Ontology.VALUE_TYPE_NAMES[comparedValueType],
Ontology.VALUE_TYPE_NAMES[originalValueType]);
}
} else if (compareTypes == TypesCompareOption.ALLOW_SUPERTYPES) {
if (!valueTypes.isA(originalValueType, comparedValueType)) {
throw new UserError(null, 965, comparedAttribute.getName(),
Ontology.VALUE_TYPE_NAMES[comparedValueType],
Ontology.VALUE_TYPE_NAMES[originalValueType]);
}
} else if (compareTypes == TypesCompareOption.ALLOW_SAME_PARENTS) {
/*
* Calculate parents. If one parent is equal to ATTRIBUITE_VALUE or less (no
* parent at all) then take the origin value.
*/
int parentOriginal = valueTypes.getParent(originalValueType);
parentOriginal = parentOriginal <= Ontology.ATTRIBUTE_VALUE ? originalValueType : parentOriginal;
int parentCompared = valueTypes.getParent(comparedValueType);
parentCompared = parentCompared <= Ontology.ATTRIBUTE_VALUE ? comparedValueType : parentCompared;
if (!valueTypes.isA(parentCompared, parentOriginal)) {
throw new UserError(op, 965, comparedAttribute.getName(),
Ontology.VALUE_TYPE_NAMES[comparedValueType],
Ontology.VALUE_TYPE_NAMES[originalValueType]);
}
} else if (compareTypes == TypesCompareOption.EQUAL) {
throw new UserError(op, 963, comparedAttribute.getName(),
Ontology.VALUE_TYPE_NAMES[originalValueType], Ontology.VALUE_TYPE_NAMES[comparedValueType]);
}
}
} else {
if (compareSets == SetsCompareOption.EQUAL) {
throw new UserError(op, 960, originalAttribute.getName());
}
if (compareSets == SetsCompareOption.ALLOW_SUPERSET) {
throw new UserError(op, 962, originalAttribute.getName());
}
}
}
for (Attribute comparedAttribute : comparedAttributes) {
if (!originalAttributes.contains(comparedAttribute)) {
if (compareSets == SetsCompareOption.EQUAL) {
throw new UserError(op, 960, comparedAttribute.getName());
}
if (compareSets == SetsCompareOption.ALLOW_SUBSET) {
throw new UserError(op, 961, comparedAttribute.getName());
}
}
}
}
}