iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.statistics.MannWhitneyUTest.java Source code

Java tutorial

Introduction

Here is the source code for iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.statistics.MannWhitneyUTest.java

Source

/* Copyright 2009-2015 David Hadka
 *
 * This file is part of the MOEA Framework.
 *
 * The MOEA Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * The MOEA Framework 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 Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with the MOEA Framework.  If not, see <http://www.gnu.org/licenses/>.
 */
package iDynoOptimizer.MOEAFramework26.src.org.moeaframework.util.statistics;

import org.apache.commons.math3.distribution.NormalDistribution;
import iDynoOptimizer.MOEAFramework26.src.org.moeaframework.core.Settings;

/**
 * The Mann-Whitney U test determines if two populations have different medians.
 * <p>
 * <ul>
 * <li>Null Hypothesis: The two populations have the same medians.
 * <li>Alternative Hypothesis: The two populations have different medians.
 * </ul>
 * <p>
 * Assumptions:
 * <ol>
 * <li>Samples are randomly selected from their corresponding populations
 * <li>Samples are independent
 * <li>The dependent variable (value being sampled) is continuous
 * <li>The underlying distributions of the populations are identical in shape
 * </ol>
 * <p>
 * References:
 * <ol>
 * <li>Sheskin, D.J. "Handbook of Parametric and Nonparametric Statistical
 * Procedures, Third Edition." Chapman & Hall/CRC. 2004.
 * </ol>
 */
public class MannWhitneyUTest extends OrdinalStatisticalTest {

    /**
     * The value of {@code U} from the last invocation of {@link #test}. This
     * is package private and intended only for testing.
     */
    double lastU;

    /**
     * Constructs a Mann-Whitney U test.
     */
    public MannWhitneyUTest() {
        super(2);
    }

    // make method public
    @Override
    public void add(double value, int group) {
        super.add(value, group);
    }

    // make method public
    @Override
    public void addAll(double[] values, int group) {
        super.addAll(values, group);
    }

    /**
     * {@inheritDoc}
     * <p>
     * When the samples from both populations are less than 20, only alpha
     * values of 0.05 and 0.01 are valid. This is because a table is used to
     * accurately determine the critical values. When more than 20 samples are
     * available, the normal approximation is used allowing any value for alpha.
     * 
     * @throws IllegalArgumentException if an insufficient sampling size is
     *         provided, or if an invalid alpha value is provided
     */
    @Override
    public boolean test(double alpha) {
        double[] R = new double[2];
        int[] n = new int[2];

        update();

        for (RankedObservation observation : data) {
            n[observation.getGroup()]++;
            R[observation.getGroup()] += observation.getRank();
        }

        double U1 = n[0] * n[1] + n[0] * (n[0] + 1) / 2.0 - R[0];
        double U2 = n[0] * n[1] + n[1] * (n[1] + 1) / 2.0 - R[1];
        double U = Math.min(U1, U2);

        // expose U for testing
        lastU = U;

        if ((n[0] <= 20) && (n[1] <= 20)) {
            return U <= getCriticalUValueFromTable(n[0], n[1], alpha);
        } else {
            double z = 0.0;
            NormalDistribution dist = new NormalDistribution();

            if (Settings.isContinuityCorrection()) {
                z = (Math.abs(U - n[0] * n[1] / 2.0) - 0.5) / Math.sqrt(n[0] * n[1] * (n[0] + n[1] + 1.0) / 12.0);
            } else {
                z = (U - n[0] * n[1] / 2.0) / Math.sqrt(n[0] * n[1] * (n[0] + n[1] + 1.0) / 12.0);
            }

            return Math.abs(z) >= Math.abs(dist.inverseCumulativeProbability(alpha));
        }
    }

    /**
     * Returns the critical U value from the lookup tables.
     * 
     * @param n1 the number of samples from the first group
     * @param n2 the number of samples from the second group
     * @param alpha the prespecified level of confidence; only values of 0.05
     *        and 0.01 are permitted
     * @return the critical U value from the lookup tables
     * @throws IllegalArgumentException if an insufficient sampling size is
     *         provided, or if an invalid alpha value is provided
     */
    private static int getCriticalUValueFromTable(int n1, int n2, double alpha) {
        if ((n1 < 1) || (n1 > 20) || (n2 < 1) || (n2 > 20)) {
            throw new IllegalArgumentException("only valid for 1 <= n1 <= 20, 1 <= n2 <= 20");
        }

        int value = -1;

        // 1 <= n1, n2 <= 20, so this subtracts 1 from each to get the 0-based
        // index
        if (alpha == 0.05) {
            value = TABLE_5[20 * n1 + n2 - 21];
        } else if (alpha == 0.01) {
            value = TABLE_1[20 * n1 + n2 - 21];
        } else {
            throw new IllegalArgumentException("only valid for 0.05 or 0.01");
        }

        if (value == -1) {
            throw new IllegalArgumentException("insufficient sampling size");
        }

        return value;
    }

    /**
     * Table of critical U values for alpha=0.05.  Entries of -1 indicate an
     * insufficient sampling size.
     */
    private static final int[] TABLE_5 = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, -1, -1, -1, -1, 0, 1,
            1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, -1, -1, -1, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12,
            13, 13, -1, -1, 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20, -1, -1, 1, 2, 3, 5, 6, 8,
            10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 25, 27, -1, -1, 1, 3, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24,
            26, 28, 30, 32, 34, -1, 0, 2, 4, 6, 8, 10, 13, 15, 17, 19, 22, 24, 26, 29, 31, 34, 36, 38, 41, -1, 0, 2,
            4, 7, 10, 12, 15, 17, 21, 23, 26, 28, 31, 34, 37, 39, 42, 45, 48, -1, 0, 3, 5, 8, 11, 14, 17, 20, 23,
            26, 29, 33, 36, 39, 42, 45, 48, 52, 55, -1, 0, 3, 6, 9, 13, 16, 19, 23, 26, 30, 33, 37, 40, 44, 47, 51,
            55, 58, 62, -1, 1, 4, 7, 11, 14, 18, 22, 26, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, -1, 1, 4, 8,
            12, 16, 20, 24, 28, 33, 37, 41, 45, 50, 54, 59, 63, 67, 72, 76, -1, 1, 5, 9, 13, 17, 22, 26, 31, 36, 40,
            45, 50, 55, 59, 64, 67, 74, 78, 83, -1, 1, 5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 70, 75,
            80, 85, 90, -1, 1, 6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75, 81, 86, 92, 98, -1, 2, 6, 11,
            17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87, 93, 99, 105, -1, 2, 7, 12, 18, 24, 30, 36, 42, 48,
            55, 61, 67, 74, 80, 86, 93, 99, 106, 112, -1, 2, 7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92,
            99, 106, 113, 119, -1, 2, 8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127 };

    /**
     * Table of critical U values for alpha=0.01.  Entries of -1 indicate an
     * insufficient sampling size.
     */
    private static final int[] TABLE_1 = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1,
            -1, -1, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, -1, -1, -1, -1, -1, 0, 0, 1, 1, 2, 2, 3, 3,
            4, 5, 5, 6, 6, 7, 8, -1, -1, -1, -1, 0, 1, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, -1, -1, -1, 0,
            1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 16, 17, 18, -1, -1, -1, 0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15,
            16, 18, 19, 21, 22, 24, -1, -1, -1, 1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 28, 30, -1,
            -1, 0, 1, 3, 5, 7, 9, 11, 13, 16, 18, 20, 22, 24, 27, 29, 31, 33, 36, -1, -1, 0, 2, 4, 6, 9, 11, 13, 16,
            18, 21, 24, 26, 29, 31, 34, 37, 39, 42, -1, -1, 0, 2, 5, 7, 10, 13, 16, 18, 21, 24, 27, 30, 33, 36, 39,
            42, 45, 46, -1, -1, 1, 3, 6, 9, 12, 15, 18, 21, 24, 27, 31, 34, 37, 41, 44, 47, 51, 54, -1, -1, 1, 3, 7,
            10, 13, 17, 20, 24, 27, 31, 34, 38, 42, 45, 49, 53, 56, 60, -1, -1, 1, 4, 7, 11, 15, 18, 22, 26, 30, 34,
            38, 42, 46, 50, 54, 58, 63, 67, -1, -1, 2, 5, 8, 12, 16, 20, 24, 29, 33, 37, 42, 46, 51, 55, 60, 64, 69,
            73, -1, -1, 2, 5, 9, 13, 18, 22, 27, 31, 36, 41, 45, 50, 55, 60, 65, 70, 74, 79, -1, -1, 2, 6, 10, 15,
            19, 24, 29, 34, 39, 44, 49, 54, 60, 65, 70, 75, 81, 86, -1, -1, 2, 6, 11, 16, 21, 26, 31, 37, 42, 47,
            53, 58, 64, 70, 75, 81, 87, 92, -1, 0, 3, 7, 12, 17, 22, 28, 33, 39, 45, 51, 56, 63, 69, 74, 81, 87, 93,
            99, -1, 0, 3, 8, 13, 18, 24, 30, 36, 42, 46, 54, 60, 67, 73, 79, 86, 92, 99, 105 };

}