You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2013/07/18 16:59:49 UTC

svn commit: r1504495 - in /commons/proper/math/trunk/src: changes/changes.xml main/java/org/apache/commons/math3/stat/StatUtils.java test/java/org/apache/commons/math3/stat/StatUtilsTest.java

Author: sebb
Date: Thu Jul 18 14:59:48 2013
New Revision: 1504495

URL: http://svn.apache.org/r1504495
Log:
MATH-1007 Add mode function to StatUtils class 

Modified:
    commons/proper/math/trunk/src/changes/changes.xml
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/StatUtils.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/StatUtilsTest.java

Modified: commons/proper/math/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/changes/changes.xml?rev=1504495&r1=1504494&r2=1504495&view=diff
==============================================================================
--- commons/proper/math/trunk/src/changes/changes.xml (original)
+++ commons/proper/math/trunk/src/changes/changes.xml Thu Jul 18 14:59:48 2013
@@ -51,6 +51,9 @@ If the output is not quite correct, chec
   </properties>
   <body>
     <release version="x.y" date="TBD" description="TBD">
+      <action dev="sebb" type="add" issue="MATH-1007">
+        Add mode function to StatUtils class
+      </action>
       <action dev="psteitz" type="update" issue="MATH-1006">
         Enabled LaTeX expressions in javadoc via MathJax.
       </action>

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/StatUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/StatUtils.java?rev=1504495&r1=1504494&r2=1504495&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/StatUtils.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/stat/StatUtils.java Thu Jul 18 14:59:48 2013
@@ -16,7 +16,11 @@
  */
 package org.apache.commons.math3.stat;
 
+import java.util.List;
+
 import org.apache.commons.math3.exception.MathIllegalArgumentException;
+import org.apache.commons.math3.exception.NotPositiveException;
+import org.apache.commons.math3.exception.NullArgumentException;
 import org.apache.commons.math3.exception.NumberIsTooSmallException;
 import org.apache.commons.math3.exception.DimensionMismatchException;
 import org.apache.commons.math3.exception.NoDataException;
@@ -791,4 +795,88 @@ public final class StatUtils {
         }
         return standardizedSample;
     }
+
+    /**
+     * Returns the sample mode(s).  The mode is the most frequently occurring
+     * value in the sample. If there is a unique value with maximum frequency,
+     * this value is returned as the only element of the output array. Otherwise,
+     * the returned array contains the maximum frequency elements in increasing
+     * order.  For example, if {@code sample} is {0, 12, 5, 6, 0, 13, 5, 17},
+     * the returned array will have length two, with 0 in the first element and
+     * 5 in the second.
+     *
+     * <p>NaN values are ignored when computing the mode - i.e., NaNs will never
+     * appear in the output array.  If the sample includes only NaNs or has
+     * length 0, an empty array is returned.</p>
+     *
+     * @param sample input data
+     * @return array of array of the most frequently occuring element(s) sorted in ascending order.
+     * @throws MathIllegalArgumentException if the indices are invalid or the array is null
+     */    
+    public static double[] mode(double[] sample) throws MathIllegalArgumentException {
+        if (sample == null) {
+            throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
+        }
+        return getMode(sample, 0, sample.length);
+    }
+
+    /**
+     * Returns the sample mode(s).  The mode is the most frequently occurring
+     * value in the sample. If there is a unique value with maximum frequency,
+     * this value is returned as the only element of the output array. Otherwise,
+     * the returned array contains the maximum frequency elements in increasing
+     * order.  For example, if {@code sample} is {0, 12, 5, 6, 0, 13, 5, 17},
+     * the returned array will have length two, with 0 in the first element and
+     * 5 in the second.
+     *
+     * <p>NaN values are ignored when computing the mode - i.e., NaNs will never
+     * appear in the output array.  If the sample includes only NaNs or has
+     * length 0, an empty array is returned.</p>
+     *
+     * @param sample input data
+     * @param begin index (0-based) of the first array element to include
+     * @param length the number of elements to include
+     *
+     * @return array of array of the most frequently occuring element(s) sorted in ascending order.
+     * @throws MathIllegalArgumentException if the indices are invalid or the array is null
+     */    
+    public static double[] mode(double[] sample, final int begin, final int length) {
+        if (sample == null) {
+            throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
+        }
+
+        if (begin < 0) {
+            throw new NotPositiveException(LocalizedFormats.START_POSITION, Integer.valueOf(begin));
+        }
+
+        if (length < 0) {
+            throw new NotPositiveException(LocalizedFormats.LENGTH, Integer.valueOf(length));
+        }
+
+        return getMode(sample, begin, length);
+    }
+
+    /*
+     * Private helper method.
+     * Assumes parameters have been validated.
+     */
+    private static double[] getMode(double[] values, final int begin, final int length) {
+        // Add the values to the frequency table
+        Frequency freq = new Frequency();
+        for (int i = begin; i < begin + length; i++) {
+            final double value = values[i];
+            if (!Double.isNaN(value)) {
+                freq.addValue(Double.valueOf(value));
+            }
+        }
+        List<Comparable<?>> list = freq.getMode();
+        // Convert the list to an array of primitive double
+        double[] modes = new double[list.size()];
+        int i = 0;
+        for(Comparable<?> c : list) {
+            modes[i++] = ((Double) c).doubleValue();
+        }
+        return modes;
+    }
+
 }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/StatUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/StatUtilsTest.java?rev=1504495&r1=1504494&r2=1504495&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/StatUtilsTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/stat/StatUtilsTest.java Thu Jul 18 14:59:48 2013
@@ -507,5 +507,42 @@ public final class StatUtilsTest {
         Assert.assertEquals(1.0, stats.getStandardDeviation(), distance);
 
     }
+    
+    @Test
+    public void testMode() {
+        final double[] singleMode = {0, 1, 0, 2, 7, 11, 12};
+        final double[] modeSingle = StatUtils.mode(singleMode);
+        Assert.assertEquals(0, modeSingle[0], Double.MIN_VALUE);
+        Assert.assertEquals(1, modeSingle.length);
+
+        final double[] twoMode = {0, 1, 2, 0, 2, 3, 7, 11};
+        final double[] modeDouble = StatUtils.mode(twoMode);
+        Assert.assertEquals(0, modeDouble[0], Double.MIN_VALUE);
+        Assert.assertEquals(2, modeDouble[1], Double.MIN_VALUE);
+        Assert.assertEquals(2, modeDouble.length);
+
+        final double[] nanInfested = {0, 0, 0, Double.NaN, Double.NaN, Double.NaN, Double.NaN, 2, 2, 2, 3, 5};
+        final double[] modeNan = StatUtils.mode(nanInfested);
+        Assert.assertEquals(0, modeNan[0], Double.MIN_VALUE);
+        Assert.assertEquals(2, modeNan[1], Double.MIN_VALUE);
+        Assert.assertEquals(2, modeNan.length);
+
+        final double[] infInfested = {0, 0, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
+            Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, 2, 2, 3, 5};
+        final double[] modeInf = StatUtils.mode(infInfested);
+        Assert.assertEquals(Double.NEGATIVE_INFINITY, modeInf[0], Double.MIN_VALUE);
+        Assert.assertEquals(0, modeInf[1], Double.MIN_VALUE);
+        Assert.assertEquals(2, modeInf[2], Double.MIN_VALUE);
+        Assert.assertEquals(Double.POSITIVE_INFINITY, modeInf[3], Double.MIN_VALUE);
+        Assert.assertEquals(4, modeInf.length);
+
+        final double[] noData = {};
+        final double[] modeNodata = StatUtils.mode(noData);
+        Assert.assertEquals(0, modeNodata.length);
+
+        final double[] nansOnly = {Double.NaN, Double.NaN};
+        final double[] modeNansOnly = StatUtils.mode(nansOnly);
+        Assert.assertEquals(0, modeNansOnly.length);
+    }
 
 }