Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
Frequency |
|
| 2.0357142857142856;2.036 |
1 | /* |
|
2 | * Copyright 2003-2004 The Apache Software Foundation. |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | package org.apache.commons.math.stat; |
|
17 | ||
18 | import java.io.Serializable; |
|
19 | import java.text.NumberFormat; |
|
20 | import java.util.Iterator; |
|
21 | import java.util.Comparator; |
|
22 | import java.util.TreeMap; |
|
23 | ||
24 | /** |
|
25 | * Maintains a frequency distribution. |
|
26 | * <p> |
|
27 | * Accepts int, long, char or Object values. New values added must be |
|
28 | * comparable to those that have been added, otherwise the add method will |
|
29 | * throw an IllegalArgumentException. |
|
30 | * <p> |
|
31 | * Integer values (int, long, Integer, Long) are not distinguished by type -- |
|
32 | * i.e. <code>addValue(new Long(2)), addValue(2), addValue(2l)</code> all have |
|
33 | * the same effect (similarly for arguments to <code>getCount,</code> etc.). |
|
34 | * <p> |
|
35 | * The values are ordered using the default (natural order), unless a |
|
36 | * <code>Comparator</code> is supplied in the constructor. |
|
37 | * |
|
38 | * @version $Revision$ $Date: 2005-02-26 05:11:52 -0800 (Sat, 26 Feb 2005) $ |
|
39 | */ |
|
40 | public class Frequency implements Serializable { |
|
41 | ||
42 | /** Serializable version identifier */ |
|
43 | static final long serialVersionUID = -3845586908418844111L; |
|
44 | ||
45 | /** underlying collection */ |
|
46 | 62 | private TreeMap freqTable = null; |
47 | ||
48 | /** |
|
49 | * Default constructor. |
|
50 | */ |
|
51 | 60 | public Frequency() { |
52 | 60 | freqTable = new TreeMap(); |
53 | 60 | } |
54 | ||
55 | /** |
|
56 | * Constructor allowing values Comparator to be specified. |
|
57 | * |
|
58 | * @param comparator Comparator used to order values |
|
59 | */ |
|
60 | 2 | public Frequency(Comparator comparator) { |
61 | 2 | freqTable = new TreeMap(comparator); |
62 | 2 | } |
63 | ||
64 | /** |
|
65 | * Return a string representation of this frequency |
|
66 | * distribution. |
|
67 | * |
|
68 | * @return a string representation. |
|
69 | */ |
|
70 | public String toString() { |
|
71 | 2 | NumberFormat nf = NumberFormat.getPercentInstance(); |
72 | 2 | StringBuffer outBuffer = new StringBuffer(); |
73 | 2 | outBuffer.append("Value \t Freq. \t Pct. \t Cum Pct. \n"); |
74 | 2 | Iterator iter = freqTable.keySet().iterator(); |
75 | 6 | while (iter.hasNext()) { |
76 | 4 | Object value = iter.next(); |
77 | 4 | outBuffer.append(value); |
78 | 4 | outBuffer.append('\t'); |
79 | 4 | outBuffer.append(getCount(value)); |
80 | 4 | outBuffer.append('\t'); |
81 | 4 | outBuffer.append(nf.format(getPct(value))); |
82 | 4 | outBuffer.append('\t'); |
83 | 4 | outBuffer.append(nf.format(getCumPct(value))); |
84 | 4 | outBuffer.append('\n'); |
85 | } |
|
86 | 2 | return outBuffer.toString(); |
87 | } |
|
88 | ||
89 | /** |
|
90 | * Adds 1 to the frequency count for v. |
|
91 | * |
|
92 | * @param v the value to add. |
|
93 | * @throws IllegalArgumentException if <code>v</code> is not comparable. |
|
94 | */ |
|
95 | public void addValue(Object v) { |
|
96 | 1286080 | Object obj = v; |
97 | 1286080 | if (v instanceof Integer) { |
98 | 2 | obj = new Long(((Integer) v).longValue()); |
99 | } |
|
100 | try { |
|
101 | 1286080 | Long count = (Long) freqTable.get(obj); |
102 | 1286078 | if (count == null) { |
103 | 432 | freqTable.put(obj, new Long(1)); |
104 | } else { |
|
105 | 1285646 | freqTable.put(obj, new Long(count.longValue() + 1)); |
106 | } |
|
107 | 2 | } catch (ClassCastException ex) { |
108 | //TreeMap will throw ClassCastException if v is not comparable |
|
109 | 2 | throw new IllegalArgumentException("Value not comparable to existing values."); |
110 | 1286078 | } |
111 | 1286078 | } |
112 | ||
113 | /** |
|
114 | * Adds 1 to the frequency count for v. |
|
115 | * |
|
116 | * @param v the value to add. |
|
117 | */ |
|
118 | public void addValue(int v) { |
|
119 | 16022 | addValue(new Long(v)); |
120 | 16022 | } |
121 | ||
122 | /** |
|
123 | * Adds 1 to the frequency count for v. |
|
124 | * |
|
125 | * @param v the value to add. |
|
126 | */ |
|
127 | public void addValue(Integer v) { |
|
128 | 6 | addValue(new Long(v.longValue())); |
129 | 6 | } |
130 | ||
131 | /** |
|
132 | * Adds 1 to the frequency count for v. |
|
133 | * |
|
134 | * @param v the value to add. |
|
135 | */ |
|
136 | public void addValue(long v) { |
|
137 | 70016 | addValue(new Long(v)); |
138 | 70016 | } |
139 | ||
140 | /** |
|
141 | * Adds 1 to the frequency count for v. |
|
142 | * |
|
143 | * @param v the value to add. |
|
144 | */ |
|
145 | public void addValue(char v) { |
|
146 | 12 | addValue(new Character(v)); |
147 | 12 | } |
148 | ||
149 | /** Clears the frequency table */ |
|
150 | public void clear() { |
|
151 | 4 | freqTable.clear(); |
152 | 4 | } |
153 | ||
154 | /** |
|
155 | * Returns an Iterator over the set of values that have been added. |
|
156 | * <p> |
|
157 | * If added values are itegral (i.e., integers, longs, Integers, or Longs), |
|
158 | * they are converted to Longs when they are added, so the objects returned |
|
159 | * by the Iterator will in this case be Longs. |
|
160 | * |
|
161 | * @return values Iterator |
|
162 | */ |
|
163 | public Iterator valuesIterator() { |
|
164 | 28 | return freqTable.keySet().iterator(); |
165 | } |
|
166 | ||
167 | //------------------------------------------------------------------------- |
|
168 | ||
169 | /** |
|
170 | * Returns the sum of all frequencies. |
|
171 | * |
|
172 | * @return the total frequency count. |
|
173 | */ |
|
174 | public long getSumFreq() { |
|
175 | 264 | long result = 0; |
176 | 264 | Iterator iterator = freqTable.values().iterator(); |
177 | 992 | while (iterator.hasNext()) { |
178 | 728 | result += ((Long) iterator.next()).longValue(); |
179 | } |
|
180 | 264 | return result; |
181 | } |
|
182 | ||
183 | /** |
|
184 | * Returns the number of values = v. |
|
185 | * |
|
186 | * @param v the value to lookup. |
|
187 | * @return the frequency of v. |
|
188 | */ |
|
189 | public long getCount(Object v) { |
|
190 | 408 | if (v instanceof Integer) { |
191 | 8 | return getCount(((Integer) v).longValue()); |
192 | } |
|
193 | 400 | long result = 0; |
194 | try { |
|
195 | 400 | Long count = (Long) freqTable.get(v); |
196 | 396 | if (count != null) { |
197 | 386 | result = count.longValue(); |
198 | } |
|
199 | 4 | } catch (ClassCastException ex) { |
200 | // ignore and return 0 -- ClassCastException will be thrown if value is not comparable |
|
201 | 396 | } |
202 | 400 | return result; |
203 | } |
|
204 | ||
205 | /** |
|
206 | * Returns the number of values = v. |
|
207 | * |
|
208 | * @param v the value to lookup. |
|
209 | * @return the frequency of v. |
|
210 | */ |
|
211 | public long getCount(int v) { |
|
212 | 152 | return getCount(new Long(v)); |
213 | } |
|
214 | ||
215 | /** |
|
216 | * Returns the number of values = v. |
|
217 | * |
|
218 | * @param v the value to lookup. |
|
219 | * @return the frequency of v. |
|
220 | */ |
|
221 | public long getCount(long v) { |
|
222 | 8 | return getCount(new Long(v)); |
223 | } |
|
224 | ||
225 | /** |
|
226 | * Returns the number of values = v. |
|
227 | * |
|
228 | * @param v the value to lookup. |
|
229 | * @return the frequency of v. |
|
230 | */ |
|
231 | public long getCount(char v) { |
|
232 | 4 | return getCount(new Character(v)); |
233 | } |
|
234 | ||
235 | //------------------------------------------------------------- |
|
236 | ||
237 | /** |
|
238 | * Returns the percentage of values that are equal to v |
|
239 | * (as a proportion between 0 and 1). |
|
240 | * <p> |
|
241 | * Returns <code>Double.NaN</code> if no values have been added. |
|
242 | * |
|
243 | * @param v the value to lookup |
|
244 | * @return the proportion of values equal to v |
|
245 | */ |
|
246 | public double getPct(Object v) { |
|
247 | 28 | if (getSumFreq() == 0) { |
248 | 6 | return Double.NaN; |
249 | } |
|
250 | 22 | return (double) getCount(v) / (double) getSumFreq(); |
251 | } |
|
252 | ||
253 | /** |
|
254 | * Returns the percentage of values that are equal to v |
|
255 | * (as a proportion between 0 and 1). |
|
256 | * |
|
257 | * @param v the value to lookup |
|
258 | * @return the proportion of values equal to v |
|
259 | */ |
|
260 | public double getPct(int v) { |
|
261 | 6 | return getPct(new Long(v)); |
262 | } |
|
263 | ||
264 | /** |
|
265 | * Returns the percentage of values that are equal to v |
|
266 | * (as a proportion between 0 and 1). |
|
267 | * |
|
268 | * @param v the value to lookup |
|
269 | * @return the proportion of values equal to v |
|
270 | */ |
|
271 | public double getPct(long v) { |
|
272 | 2 | return getPct(new Long(v)); |
273 | } |
|
274 | ||
275 | /** |
|
276 | * Returns the percentage of values that are equal to v |
|
277 | * (as a proportion between 0 and 1). |
|
278 | * |
|
279 | * @param v the value to lookup |
|
280 | * @return the proportion of values equal to v |
|
281 | */ |
|
282 | public double getPct(char v) { |
|
283 | 6 | return getPct(new Character(v)); |
284 | } |
|
285 | ||
286 | //----------------------------------------------------------------------------------------- |
|
287 | ||
288 | /** |
|
289 | * Returns the cumulative frequency of values less than or equal to v. |
|
290 | * <p> |
|
291 | * Returns 0 if v is not comparable to the values set. |
|
292 | * |
|
293 | * @param v the value to lookup. |
|
294 | * @return the proportion of values equal to v |
|
295 | */ |
|
296 | public long getCumFreq(Object v) { |
|
297 | 74 | if (getSumFreq() == 0) { |
298 | 6 | return 0; |
299 | } |
|
300 | 68 | if (v instanceof Integer) { |
301 | 6 | return getCumFreq(((Integer) v).longValue()); |
302 | } |
|
303 | 62 | Comparator c = freqTable.comparator(); |
304 | 62 | if (c == null) { |
305 | 58 | c = new NaturalComparator(); |
306 | } |
|
307 | 62 | long result = 0; |
308 | ||
309 | try { |
|
310 | 62 | Long value = (Long) freqTable.get(v); |
311 | 56 | if (value != null) { |
312 | 36 | result = value.longValue(); |
313 | } |
|
314 | 6 | } catch (ClassCastException ex) { |
315 | 6 | return result; // v is not comparable |
316 | 56 | } |
317 | ||
318 | 56 | if (c.compare(v, freqTable.firstKey()) < 0) { |
319 | 6 | return 0; // v is comparable, but less than first value |
320 | } |
|
321 | ||
322 | 50 | if (c.compare(v, freqTable.lastKey()) >= 0) { |
323 | 24 | return getSumFreq(); // v is comparable, but greater than the last value |
324 | } |
|
325 | ||
326 | 26 | Iterator values = valuesIterator(); |
327 | 40 | while (values.hasNext()) { |
328 | 40 | Object nextValue = values.next(); |
329 | 40 | if (c.compare(v, nextValue) > 0) { |
330 | 14 | result += getCount(nextValue); |
331 | } else { |
|
332 | 26 | return result; |
333 | } |
|
334 | } |
|
335 | 0 | return result; |
336 | } |
|
337 | ||
338 | /** |
|
339 | * Returns the cumulative frequency of values less than or equal to v. |
|
340 | * <p> |
|
341 | * Returns 0 if v is not comparable to the values set. |
|
342 | * |
|
343 | * @param v the value to lookup |
|
344 | * @return the proportion of values equal to v |
|
345 | */ |
|
346 | public long getCumFreq(int v) { |
|
347 | 10 | return getCumFreq(new Long(v)); |
348 | } |
|
349 | ||
350 | /** |
|
351 | * Returns the cumulative frequency of values less than or equal to v. |
|
352 | * <p> |
|
353 | * Returns 0 if v is not comparable to the values set. |
|
354 | * |
|
355 | * @param v the value to lookup |
|
356 | * @return the proportion of values equal to v |
|
357 | */ |
|
358 | public long getCumFreq(long v) { |
|
359 | 6 | return getCumFreq(new Long(v)); |
360 | } |
|
361 | ||
362 | /** |
|
363 | * Returns the cumulative frequency of values less than or equal to v. |
|
364 | * <p> |
|
365 | * Returns 0 if v is not comparable to the values set. |
|
366 | * |
|
367 | * @param v the value to lookup |
|
368 | * @return the proportion of values equal to v |
|
369 | */ |
|
370 | public long getCumFreq(char v) { |
|
371 | 4 | return getCumFreq(new Character(v)); |
372 | } |
|
373 | ||
374 | //---------------------------------------------------------------------------------------------- |
|
375 | ||
376 | /** |
|
377 | * Returns the cumulative percentage of values less than or equal to v |
|
378 | * (as a proportion between 0 and 1). |
|
379 | * <p> |
|
380 | * Returns <code>Double.NaN</code> if no values have been added. |
|
381 | * Returns 0 if at least one value has been added, but v is not comparable |
|
382 | * to the values set. |
|
383 | * |
|
384 | * @param v the value to lookup |
|
385 | * @return the proportion of values less than or equal to v |
|
386 | */ |
|
387 | public double getCumPct(Object v) { |
|
388 | 54 | if (getSumFreq() == 0) { |
389 | 6 | return Double.NaN; |
390 | } |
|
391 | 48 | return (double) getCumFreq(v) / (double) getSumFreq(); |
392 | } |
|
393 | ||
394 | /** |
|
395 | * Returns the cumulative percentage of values less than or equal to v |
|
396 | * (as a proportion between 0 and 1). |
|
397 | * <p> |
|
398 | * Returns 0 if v is not comparable to the values set. |
|
399 | * |
|
400 | * @param v the value to lookup |
|
401 | * @return the proportion of values less than or equal to v |
|
402 | */ |
|
403 | public double getCumPct(int v) { |
|
404 | 16 | return getCumPct(new Long(v)); |
405 | } |
|
406 | ||
407 | /** |
|
408 | * Returns the cumulative percentage of values less than or equal to v |
|
409 | * (as a proportion between 0 and 1). |
|
410 | * <p> |
|
411 | * Returns 0 if v is not comparable to the values set. |
|
412 | * |
|
413 | * @param v the value to lookup |
|
414 | * @return the proportion of values less than or equal to v |
|
415 | */ |
|
416 | public double getCumPct(long v) { |
|
417 | 2 | return getCumPct(new Long(v)); |
418 | } |
|
419 | ||
420 | /** |
|
421 | * Returns the cumulative percentage of values less than or equal to v |
|
422 | * (as a proportion between 0 and 1). |
|
423 | * <p> |
|
424 | * Returns 0 if v is not comparable to the values set. |
|
425 | * |
|
426 | * @param v the value to lookup |
|
427 | * @return the proportion of values less than or equal to v |
|
428 | */ |
|
429 | public double getCumPct(char v) { |
|
430 | 8 | return getCumPct(new Character(v)); |
431 | } |
|
432 | ||
433 | /** |
|
434 | * A Comparator that compares comparable objects using the |
|
435 | * natural order. Copied from Commons Collections ComparableComparator. |
|
436 | */ |
|
437 | 116 | private static class NaturalComparator implements Comparator { |
438 | /** |
|
439 | * Compare the two {@link Comparable Comparable} arguments. |
|
440 | * This method is equivalent to: |
|
441 | * <pre>(({@link Comparable Comparable})o1).{@link Comparable#compareTo compareTo}(o2)</pre> |
|
442 | * |
|
443 | * @param o1 the first object |
|
444 | * @param o2 the second object |
|
445 | * @return result of comparison |
|
446 | * @throws NullPointerException when <i>o1</i> is <code>null</code>, |
|
447 | * or when <code>((Comparable)o1).compareTo(o2)</code> does |
|
448 | * @throws ClassCastException when <i>o1</i> is not a {@link Comparable Comparable}, |
|
449 | * or when <code>((Comparable)o1).compareTo(o2)</code> does |
|
450 | */ |
|
451 | public int compare(Object o1, Object o2) { |
|
452 | 138 | return ((Comparable)o1).compareTo(o2); |
453 | } |
|
454 | } |
|
455 | } |