Coverage Report - org.apache.commons.math.stat.Frequency

Classes in this File Line Coverage Branch Coverage Complexity
Frequency
99% 
100% 
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  
 }