001: /*
002: * This program is free software; you can redistribute it and/or modify
003: * it under the terms of the GNU General Public License as published by
004: * the Free Software Foundation; either version 2 of the License, or
005: * (at your option) any later version.
006: *
007: * This program is distributed in the hope that it will be useful,
008: * but WITHOUT ANY WARRANTY; without even the implied warranty of
009: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: * GNU General Public License for more details.
011: *
012: * You should have received a copy of the GNU General Public License
013: * along with this program; if not, write to the Free Software
014: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
015: */
016:
017: /*
018: * InstanceComparator.java
019: * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
020: *
021: */
022:
023: package weka.core;
024:
025: import java.io.BufferedReader;
026: import java.io.FileReader;
027: import java.io.Serializable;
028: import java.util.Comparator;
029:
030: /**
031: * A comparator for the Instance class. it can be used with or without the
032: * class label. Missing values are sorted at the beginning.<br>
033: * Can be used as comparator in the sorting and binary search algorithms of
034: * <code>Arrays</code> and <code>Collections</code>.
035: *
036: * @see Instance
037: * @author FracPete (fracpete at cs dot waikato dot ac dot nz)
038: * @version $Revision: 1.3 $
039: * @see java.util.Arrays
040: * @see java.util.Collections
041: */
042: public class InstanceComparator implements Comparator, Serializable {
043:
044: /** for serialization */
045: private static final long serialVersionUID = -6589278678230949683L;
046:
047: /** whether to include the class in the comparison */
048: protected boolean m_IncludeClass;
049:
050: /**
051: * initializes the comparator and includes the class in the comparison
052: */
053: public InstanceComparator() {
054: this (true);
055: }
056:
057: /**
058: * initializes the comparator
059: */
060: public InstanceComparator(boolean includeClass) {
061: super ();
062: setIncludeClass(includeClass);
063: }
064:
065: /**
066: * sets whether the class should be included (= TRUE) in the comparison
067: *
068: * @param includeClass whether to include the class in the comparison
069: */
070: public void setIncludeClass(boolean includeClass) {
071: m_IncludeClass = includeClass;
072: }
073:
074: /**
075: * returns TRUE if the class is included in the comparison
076: */
077: public boolean getIncludeClass() {
078: return m_IncludeClass;
079: }
080:
081: /**
082: * compares the two instances, returns -1 if o1 is smaller than o2, 0
083: * if equal and +1 if greater. The method assumes that both instance objects
084: * have the same attributes, they don't have to belong to the same dataset.
085: *
086: * @param o1 the first instance to compare
087: * @param o2 the second instance to compare
088: * @return returns -1 if o1 is smaller than o2, 0 if equal and +1
089: * if greater
090: */
091: public int compare(Object o1, Object o2) {
092: int result;
093: Instance inst1;
094: Instance inst2;
095: int classindex;
096: int i;
097:
098: inst1 = (Instance) o1;
099: inst2 = (Instance) o2;
100:
101: // get class index
102: if (inst1.classIndex() == -1)
103: classindex = inst1.numAttributes() - 1;
104: else
105: classindex = inst1.classIndex();
106:
107: result = 0;
108: for (i = 0; i < inst1.numAttributes(); i++) {
109: // exclude class?
110: if (!getIncludeClass() && (i == classindex))
111: continue;
112:
113: // comparing attribute values
114: // 1. special handling if missing value (NaN) is involved:
115: if (inst1.isMissing(i) || inst2.isMissing(i)) {
116: if (inst1.isMissing(i) && inst2.isMissing(i)) {
117: continue;
118: } else {
119: if (inst1.isMissing(i))
120: result = -1;
121: else
122: result = 1;
123: break;
124: }
125: }
126: // 2. regular values:
127: else {
128: if (Utils.eq(inst1.value(i), inst2.value(i))) {
129: continue;
130: } else {
131: if (inst1.value(i) < inst2.value(i))
132: result = -1;
133: else
134: result = 1;
135: break;
136: }
137: }
138: }
139:
140: return result;
141: }
142:
143: /**
144: * for testing only. takes an ARFF-filename as first argument to perform
145: * some tests.
146: */
147: public static void main(String[] args) throws Exception {
148: Instances inst;
149: Comparator comp;
150:
151: if (args.length == 0)
152: return;
153:
154: // read instances
155: inst = new Instances(
156: new BufferedReader(new FileReader(args[0])));
157: inst.setClassIndex(inst.numAttributes() - 1);
158:
159: // compare incl. class
160: comp = new InstanceComparator();
161: System.out.println("\nIncluding the class");
162: System.out.println("comparing 1. instance with 1.: "
163: + comp.compare(inst.instance(0), inst.instance(0)));
164: System.out.println("comparing 1. instance with 2.: "
165: + comp.compare(inst.instance(0), inst.instance(1)));
166: System.out.println("comparing 2. instance with 1.: "
167: + comp.compare(inst.instance(1), inst.instance(0)));
168:
169: // compare excl. class
170: comp = new InstanceComparator(false);
171: System.out.println("\nExcluding the class");
172: System.out.println("comparing 1. instance with 1.: "
173: + comp.compare(inst.instance(0), inst.instance(0)));
174: System.out.println("comparing 1. instance with 2.: "
175: + comp.compare(inst.instance(0), inst.instance(1)));
176: System.out.println("comparing 2. instance with 1.: "
177: + comp.compare(inst.instance(1), inst.instance(0)));
178: }
179: }
|