    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.math3.stat.inference;
    018
    019    import org.apache.commons.math3.distribution.ChiSquaredDistribution;
    020    import org.apache.commons.math3.exception.DimensionMismatchException;
    021    import org.apache.commons.math3.exception.MaxCountExceededException;
    022    import org.apache.commons.math3.exception.NotPositiveException;
    023    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
    024    import org.apache.commons.math3.exception.NullArgumentException;
    025    import org.apache.commons.math3.exception.OutOfRangeException;
    026    import org.apache.commons.math3.exception.ZeroException;
    027    import org.apache.commons.math3.exception.util.LocalizedFormats;
    028    import org.apache.commons.math3.util.FastMath;
    029    import org.apache.commons.math3.util.MathArrays;
    030
    031    /**
    032     * Implements Chi-Square test statistics.
    033     *
    034     * <p>This implementation handles both known and unknown distributions.</p>
    035     *
    036     * <p>Two samples tests can be used when the distribution is unknown <i>a priori</i>
    037     * but provided by one sample, or when the hypothesis under test is that the two
    038     * samples come from the same underlying distribution.</p>
    039     *
    040     * @version $Id: ChiSquareTest.java 1416643 2012-12-03 19:37:14Z tn $
    041     */
    042    public class ChiSquareTest {
    043
    044        /**
    045         * Construct a ChiSquareTest
    046         */
    047        public ChiSquareTest() {
    048            super();
    049        }
    050
    051        /**
    052         * Computes the <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda35f.htm">
    053         * Chi-Square statistic</a> comparing <code>observed</code> and <code>expected</code>
    054         * frequency counts.
    055         * <p>
    056         * This statistic can be used to perform a Chi-Square test evaluating the null
    057         * hypothesis that the observed counts follow the expected distribution.</p>
    058         * <p>
    059         * <strong>Preconditions</strong>: <ul>
    060         * <li>Expected counts must all be positive.
    061         * </li>
    062         * <li>Observed counts must all be &ge; 0.
    063         * </li>
    064         * <li>The observed and expected arrays must have the same length and
    065         * their common length must be at least 2.
    066         * </li></ul></p><p>
    067         * If any of the preconditions are not met, an
    068         * <code>IllegalArgumentException</code> is thrown.</p>
    069         * <p><strong>Note: </strong>This implementation rescales the
    070         * <code>expected</code> array if necessary to ensure that the sum of the
    071         * expected and observed counts are equal.</p>
    072         *
    073         * @param observed array of observed frequency counts
    074         * @param expected array of expected frequency counts
    075         * @return chiSquare test statistic
    076         * @throws NotPositiveException if <code>observed</code> has negative entries
    077         * @throws NotStrictlyPositiveException if <code>expected</code> has entries that are
    078         * not strictly positive
    079         * @throws DimensionMismatchException if the arrays length is less than 2
    080         */
    081        public double chiSquare(final double[] expected, final long[] observed)
    082            throws NotPositiveException, NotStrictlyPositiveException,
    083            DimensionMismatchException {
    084
    085            if (expected.length < 2) {
    086                throw new DimensionMismatchException(expected.length, 2);
    087            }
    088            if (expected.length != observed.length) {
    089                throw new DimensionMismatchException(expected.length, observed.length);
    090            }
    091            MathArrays.checkPositive(expected);
    092            MathArrays.checkNonNegative(observed);
    093
    094            double sumExpected = 0d;
    095            double sumObserved = 0d;
    096            for (int i = 0; i < observed.length; i++) {
    097                sumExpected += expected[i];
    098                sumObserved += observed[i];
    099            }
    100            double ratio = 1.0d;
    101            boolean rescale = false;
    102            if (FastMath.abs(sumExpected - sumObserved) > 10E-6) {
    103                ratio = sumObserved / sumExpected;
    104                rescale = true;
    105            }
    106            double sumSq = 0.0d;
    107            for (int i = 0; i < observed.length; i++) {
    108                if (rescale) {
    109                    final double dev = observed[i] - ratio * expected[i];
    110                    sumSq += dev * dev / (ratio * expected[i]);
    111                } else {
    112                    final double dev = observed[i] - expected[i];
    113                    sumSq += dev * dev / expected[i];
    114                }
    115            }
    116            return sumSq;
    117
    118        }
    119
    120        /**
    121         * Returns the <i>observed significance level</i>, or <a href=
    122         * "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
    123         * p-value</a>, associated with a
    124         * <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda35f.htm">
    125         * Chi-square goodness of fit test</a> comparing the <code>observed</code>
    126         * frequency counts to those in the <code>expected</code> array.
    127         * <p>
    128         * The number returned is the smallest significance level at which one can reject
    129         * the null hypothesis that the observed counts conform to the frequency distribution
    130         * described by the expected counts.</p>
    131         * <p>
    132         * <strong>Preconditions</strong>: <ul>
    133         * <li>Expected counts must all be positive.
    134         * </li>
    135         * <li>Observed counts must all be &ge; 0.
    136         * </li>
    137         * <li>The observed and expected arrays must have the same length and
    138         * their common length must be at least 2.
    139         * </li></ul></p><p>
    140         * If any of the preconditions are not met, an
    141         * <code>IllegalArgumentException</code> is thrown.</p>
    142         * <p><strong>Note: </strong>This implementation rescales the
    143         * <code>expected</code> array if necessary to ensure that the sum of the
    144         * expected and observed counts are equal.</p>
    145         *
    146         * @param observed array of observed frequency counts
    147         * @param expected array of expected frequency counts
    148         * @return p-value
    149         * @throws NotPositiveException if <code>observed</code> has negative entries
    150         * @throws NotStrictlyPositiveException if <code>expected</code> has entries that are
    151         * not strictly positive
    152         * @throws DimensionMismatchException if the arrays length is less than 2
    153         * @throws MaxCountExceededException if an error occurs computing the p-value
    154         */
    155        public double chiSquareTest(final double[] expected, final long[] observed)
    156            throws NotPositiveException, NotStrictlyPositiveException,
    157            DimensionMismatchException, MaxCountExceededException {
    158
    159            ChiSquaredDistribution distribution =
    160                new ChiSquaredDistribution(expected.length - 1.0);
    161            return 1.0 - distribution.cumulativeProbability(chiSquare(expected, observed));
    162        }
    163
    164        /**
    165         * Performs a <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda35f.htm">
    166         * Chi-square goodness of fit test</a> evaluating the null hypothesis that the
    167         * observed counts conform to the frequency distribution described by the expected
    168         * counts, with significance level <code>alpha</code>.  Returns true iff the null
    169         * hypothesis can be rejected with 100 * (1 - alpha) percent confidence.
    170         * <p>
    171         * <strong>Example:</strong><br>
    172         * To test the hypothesis that <code>observed</code> follows
    173         * <code>expected</code> at the 99% level, use </p><p>
    174         * <code>chiSquareTest(expected, observed, 0.01) </code></p>
    175         * <p>
    176         * <strong>Preconditions</strong>: <ul>
    177         * <li>Expected counts must all be positive.
    178         * </li>
    179         * <li>Observed counts must all be &ge; 0.
    180         * </li>
    181         * <li>The observed and expected arrays must have the same length and
    182         * their common length must be at least 2.
    183         * <li> <code> 0 &lt; alpha &lt; 0.5 </code>
    184         * </li></ul></p><p>
    185         * If any of the preconditions are not met, an
    186         * <code>IllegalArgumentException</code> is thrown.</p>
    187         * <p><strong>Note: </strong>This implementation rescales the
    188         * <code>expected</code> array if necessary to ensure that the sum of the
    189         * expected and observed counts are equal.</p>
    190         *
    191         * @param observed array of observed frequency counts
    192         * @param expected array of expected frequency counts
    193         * @param alpha significance level of the test
    194         * @return true iff null hypothesis can be rejected with confidence
    195         * 1 - alpha
    196         * @throws NotPositiveException if <code>observed</code> has negative entries
    197         * @throws NotStrictlyPositiveException if <code>expected</code> has entries that are
    198         * not strictly positive
    199         * @throws DimensionMismatchException if the arrays length is less than 2
    200         * @throws OutOfRangeException if <code>alpha</code> is not in the range (0, 0.5]
    201         * @throws MaxCountExceededException if an error occurs computing the p-value
    202         */
    203        public boolean chiSquareTest(final double[] expected, final long[] observed,
    204                                     final double alpha)
    205            throws NotPositiveException, NotStrictlyPositiveException,
    206            DimensionMismatchException, OutOfRangeException, MaxCountExceededException {
    207
    208            if ((alpha <= 0) || (alpha > 0.5)) {
    209                throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUND_SIGNIFICANCE_LEVEL,
    210                                              alpha, 0, 0.5);
    211            }
    212            return chiSquareTest(expected, observed) < alpha;
    213
    214        }
    215
    216        /**
    217         *  Computes the Chi-Square statistic associated with a
    218         * <a href="http://www.itl.nist.gov/div898/handbook/prc/section4/prc45.htm">
    219         *  chi-square test of independence</a> based on the input <code>counts</code>
    220         *  array, viewed as a two-way table.
    221         * <p>
    222         * The rows of the 2-way table are
    223         * <code>count[0], ... , count[count.length - 1] </code></p>
    224         * <p>
    225         * <strong>Preconditions</strong>: <ul>
    226         * <li>All counts must be &ge; 0.
    227         * </li>
    228         * <li>The count array must be rectangular (i.e. all count[i] subarrays
    229         *  must have the same length).
    230         * </li>
    231         * <li>The 2-way table represented by <code>counts</code> must have at
    232         *  least 2 columns and at least 2 rows.
    233         * </li>
    234         * </li></ul></p><p>
    235         * If any of the preconditions are not met, an
    236         * <code>IllegalArgumentException</code> is thrown.</p>
    237         *
    238         * @param counts array representation of 2-way table
    239         * @return chiSquare test statistic
    240         * @throws NullArgumentException if the array is null
    241         * @throws DimensionMismatchException if the array is not rectangular
    242         * @throws NotPositiveException if {@code counts} has negative entries
    243         */
    244        public double chiSquare(final long[][] counts)
    245            throws NullArgumentException, NotPositiveException,
    246            DimensionMismatchException {
    247
    248            checkArray(counts);
    249            int nRows = counts.length;
    250            int nCols = counts[0].length;
    251
    252            // compute row, column and total sums
    253            double[] rowSum = new double[nRows];
    254            double[] colSum = new double[nCols];
    255            double total = 0.0d;
    256            for (int row = 0; row < nRows; row++) {
    257                for (int col = 0; col < nCols; col++) {
    258                    rowSum[row] += counts[row][col];
    259                    colSum[col] += counts[row][col];
    260                    total += counts[row][col];
    261                }
    262            }
    263
    264            // compute expected counts and chi-square
    265            double sumSq = 0.0d;
    266            double expected = 0.0d;
    267            for (int row = 0; row < nRows; row++) {
    268                for (int col = 0; col < nCols; col++) {
    269                    expected = (rowSum[row] * colSum[col]) / total;
    270                    sumSq += ((counts[row][col] - expected) *
    271                            (counts[row][col] - expected)) / expected;
    272                }
    273            }
    274            return sumSq;
    275
    276        }
    277
    278        /**
    279         * Returns the <i>observed significance level</i>, or <a href=
    280         * "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
    281         * p-value</a>, associated with a
    282         * <a href="http://www.itl.nist.gov/div898/handbook/prc/section4/prc45.htm">
    283         * chi-square test of independence</a> based on the input <code>counts</code>
    284         * array, viewed as a two-way table.
    285         * <p>
    286         * The rows of the 2-way table are
    287         * <code>count[0], ... , count[count.length - 1] </code></p>
    288         * <p>
    289         * <strong>Preconditions</strong>: <ul>
    290         * <li>All counts must be &ge; 0.
    291         * </li>
    292         * <li>The count array must be rectangular (i.e. all count[i] subarrays must have
    293         *     the same length).
    294         * </li>
    295         * <li>The 2-way table represented by <code>counts</code> must have at least 2
    296         *     columns and at least 2 rows.
    297         * </li>
    298         * </li></ul></p><p>
    299         * If any of the preconditions are not met, an
    300         * <code>IllegalArgumentException</code> is thrown.</p>
    301         *
    302         * @param counts array representation of 2-way table
    303         * @return p-value
    304         * @throws NullArgumentException if the array is null
    305         * @throws DimensionMismatchException if the array is not rectangular
    306         * @throws NotPositiveException if {@code counts} has negative entries
    307         * @throws MaxCountExceededException if an error occurs computing the p-value
    308         */
    309        public double chiSquareTest(final long[][] counts)
    310            throws NullArgumentException, DimensionMismatchException,
    311            NotPositiveException, MaxCountExceededException {
    312
    313            checkArray(counts);
    314            double df = ((double) counts.length -1) * ((double) counts[0].length - 1);
    315            ChiSquaredDistribution distribution;
    316            distribution = new ChiSquaredDistribution(df);
    317            return 1 - distribution.cumulativeProbability(chiSquare(counts));
    318
    319        }
    320
    321        /**
    322         * Performs a <a href="http://www.itl.nist.gov/div898/handbook/prc/section4/prc45.htm">
    323         * chi-square test of independence</a> evaluating the null hypothesis that the
    324         * classifications represented by the counts in the columns of the input 2-way table
    325         * are independent of the rows, with significance level <code>alpha</code>.
    326         * Returns true iff the null hypothesis can be rejected with 100 * (1 - alpha) percent
    327         * confidence.
    328         * <p>
    329         * The rows of the 2-way table are
    330         * <code>count[0], ... , count[count.length - 1] </code></p>
    331         * <p>
    332         * <strong>Example:</strong><br>
    333         * To test the null hypothesis that the counts in
    334         * <code>count[0], ... , count[count.length - 1] </code>
    335         *  all correspond to the same underlying probability distribution at the 99% level, use</p>
    336         * <p><code>chiSquareTest(counts, 0.01)</code></p>
    337         * <p>
    338         * <strong>Preconditions</strong>: <ul>
    339         * <li>All counts must be &ge; 0.
    340         * </li>
    341         * <li>The count array must be rectangular (i.e. all count[i] subarrays must have the
    342         *     same length).</li>
    343         * <li>The 2-way table represented by <code>counts</code> must have at least 2 columns and
    344         *     at least 2 rows.</li>
    345         * </li></ul></p><p>
    346         * If any of the preconditions are not met, an
    347         * <code>IllegalArgumentException</code> is thrown.</p>
    348         *
    349         * @param counts array representation of 2-way table
    350         * @param alpha significance level of the test
    351         * @return true iff null hypothesis can be rejected with confidence
    352         * 1 - alpha
    353         * @throws NullArgumentException if the array is null
    354         * @throws DimensionMismatchException if the array is not rectangular
    355         * @throws NotPositiveException if {@code counts} has any negative entries
    356         * @throws OutOfRangeException if <code>alpha</code> is not in the range (0, 0.5]
    357         * @throws MaxCountExceededException if an error occurs computing the p-value
    358         */
    359        public boolean chiSquareTest(final long[][] counts, final double alpha)
    360            throws NullArgumentException, DimensionMismatchException,
    361            NotPositiveException, OutOfRangeException, MaxCountExceededException {
    362
    363            if ((alpha <= 0) || (alpha > 0.5)) {
    364                throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUND_SIGNIFICANCE_LEVEL,
    365                                              alpha, 0, 0.5);
    366            }
    367            return chiSquareTest(counts) < alpha;
    368
    369        }
    370
    371        /**
    372         * <p>Computes a
    373         * <a href="http://www.itl.nist.gov/div898/software/dataplot/refman1/auxillar/chi2samp.htm">
    374         * Chi-Square two sample test statistic</a> comparing bin frequency counts
    375         * in <code>observed1</code> and <code>observed2</code>.  The
    376         * sums of frequency counts in the two samples are not required to be the
    377         * same.  The formula used to compute the test statistic is</p>
    378         * <code>
    379         * &sum;[(K * observed1[i] - observed2[i]/K)<sup>2</sup> / (observed1[i] + observed2[i])]
    380         * </code> where
    381         * <br/><code>K = &sqrt;[&sum(observed2 / &sum;(observed1)]</code>
    382         * </p>
    383         * <p>This statistic can be used to perform a Chi-Square test evaluating the
    384         * null hypothesis that both observed counts follow the same distribution.</p>
    385         * <p>
    386         * <strong>Preconditions</strong>: <ul>
    387         * <li>Observed counts must be non-negative.
    388         * </li>
    389         * <li>Observed counts for a specific bin must not both be zero.
    390         * </li>
    391         * <li>Observed counts for a specific sample must not all be 0.
    392         * </li>
    393         * <li>The arrays <code>observed1</code> and <code>observed2</code> must have
    394         * the same length and their common length must be at least 2.
    395         * </li></ul></p><p>
    396         * If any of the preconditions are not met, an
    397         * <code>IllegalArgumentException</code> is thrown.</p>
    398         *
    399         * @param observed1 array of observed frequency counts of the first data set
    400         * @param observed2 array of observed frequency counts of the second data set
    401         * @return chiSquare test statistic
    402         * @throws DimensionMismatchException the the length of the arrays does not match
    403         * @throws NotPositiveException if any entries in <code>observed1</code> or
    404         * <code>observed2</code> are negative
    405         * @throws ZeroException if either all counts of <code>observed1</code> or
    406         * <code>observed2</code> are zero, or if the count at some index is zero
    407         * for both arrays
    408         * @since 1.2
    409         */
    410        public double chiSquareDataSetsComparison(long[] observed1, long[] observed2)
    411            throws DimensionMismatchException, NotPositiveException, ZeroException {
    412
    413            // Make sure lengths are same
    414            if (observed1.length < 2) {
    415                throw new DimensionMismatchException(observed1.length, 2);
    416            }
    417            if (observed1.length != observed2.length) {
    418                throw new DimensionMismatchException(observed1.length, observed2.length);
    419            }
    420
    421            // Ensure non-negative counts
    422            MathArrays.checkNonNegative(observed1);
    423            MathArrays.checkNonNegative(observed2);
    424
    425            // Compute and compare count sums
    426            long countSum1 = 0;
    427            long countSum2 = 0;
    428            boolean unequalCounts = false;
    429            double weight = 0.0;
    430            for (int i = 0; i < observed1.length; i++) {
    431                countSum1 += observed1[i];
    432                countSum2 += observed2[i];
    433            }
    434            // Ensure neither sample is uniformly 0
    435            if (countSum1 == 0 || countSum2 == 0) {
    436                throw new ZeroException();
    437            }
    438            // Compare and compute weight only if different
    439            unequalCounts = countSum1 != countSum2;
    440            if (unequalCounts) {
    441                weight = FastMath.sqrt((double) countSum1 / (double) countSum2);
    442            }
    443            // Compute ChiSquare statistic
    444            double sumSq = 0.0d;
    445            double dev = 0.0d;
    446            double obs1 = 0.0d;
    447            double obs2 = 0.0d;
    448            for (int i = 0; i < observed1.length; i++) {
    449                if (observed1[i] == 0 && observed2[i] == 0) {
    450                    throw new ZeroException(LocalizedFormats.OBSERVED_COUNTS_BOTTH_ZERO_FOR_ENTRY, i);
    451                } else {
    452                    obs1 = observed1[i];
    453                    obs2 = observed2[i];
    454                    if (unequalCounts) { // apply weights
    455                        dev = obs1/weight - obs2 * weight;
    456                    } else {
    457                        dev = obs1 - obs2;
    458                    }
    459                    sumSq += (dev * dev) / (obs1 + obs2);
    460                }
    461            }
    462            return sumSq;
    463        }
    464
    465        /**
    466         * <p>Returns the <i>observed significance level</i>, or <a href=
    467         * "http://www.cas.lancs.ac.uk/glossary_v1.1/hyptest.html#pvalue">
    468         * p-value</a>, associated with a Chi-Square two sample test comparing
    469         * bin frequency counts in <code>observed1</code> and
    470         * <code>observed2</code>.
    471         * </p>
    472         * <p>The number returned is the smallest significance level at which one
    473         * can reject the null hypothesis that the observed counts conform to the
    474         * same distribution.
    475         * </p>
    476         * <p>See {@link #chiSquareDataSetsComparison(long[], long[])} for details
    477         * on the formula used to compute the test statistic. The degrees of
    478         * of freedom used to perform the test is one less than the common length
    479         * of the input observed count arrays.
    480         * </p>
    481         * <strong>Preconditions</strong>: <ul>
    482         * <li>Observed counts must be non-negative.
    483         * </li>
    484         * <li>Observed counts for a specific bin must not both be zero.
    485         * </li>
    486         * <li>Observed counts for a specific sample must not all be 0.
    487         * </li>
    488         * <li>The arrays <code>observed1</code> and <code>observed2</code> must
    489         * have the same length and
    490         * their common length must be at least 2.
    491         * </li></ul><p>
    492         * If any of the preconditions are not met, an
    493         * <code>IllegalArgumentException</code> is thrown.</p>
    494         *
    495         * @param observed1 array of observed frequency counts of the first data set
    496         * @param observed2 array of observed frequency counts of the second data set
    497         * @return p-value
    498         * @throws DimensionMismatchException the the length of the arrays does not match
    499         * @throws NotPositiveException if any entries in <code>observed1</code> or
    500         * <code>observed2</code> are negative
    501         * @throws ZeroException if either all counts of <code>observed1</code> or
    502         * <code>observed2</code> are zero, or if the count at the same index is zero
    503         * for both arrays
    504         * @throws MaxCountExceededException if an error occurs computing the p-value
    505         * @since 1.2
    506         */
    507        public double chiSquareTestDataSetsComparison(long[] observed1, long[] observed2)
    508            throws DimensionMismatchException, NotPositiveException, ZeroException,
    509            MaxCountExceededException {
    510
    511            ChiSquaredDistribution distribution;
    512            distribution = new ChiSquaredDistribution((double) observed1.length - 1);
    513            return 1 - distribution.cumulativeProbability(
    514                    chiSquareDataSetsComparison(observed1, observed2));
    515
    516        }
    517
    518        /**
    519         * <p>Performs a Chi-Square two sample test comparing two binned data
    520         * sets. The test evaluates the null hypothesis that the two lists of
    521         * observed counts conform to the same frequency distribution, with
    522         * significance level <code>alpha</code>.  Returns true iff the null
    523         * hypothesis can be rejected with 100 * (1 - alpha) percent confidence.
    524         * </p>
    525         * <p>See {@link #chiSquareDataSetsComparison(long[], long[])} for
    526         * details on the formula used to compute the Chisquare statistic used
    527         * in the test. The degrees of of freedom used to perform the test is
    528         * one less than the common length of the input observed count arrays.
    529         * </p>
    530         * <strong>Preconditions</strong>: <ul>
    531         * <li>Observed counts must be non-negative.
    532         * </li>
    533         * <li>Observed counts for a specific bin must not both be zero.
    534         * </li>
    535         * <li>Observed counts for a specific sample must not all be 0.
    536         * </li>
    537         * <li>The arrays <code>observed1</code> and <code>observed2</code> must
    538         * have the same length and their common length must be at least 2.
    539         * </li>
    540         * <li> <code> 0 < alpha < 0.5 </code>
    541         * </li></ul><p>
    542         * If any of the preconditions are not met, an
    543         * <code>IllegalArgumentException</code> is thrown.</p>
    544         *
    545         * @param observed1 array of observed frequency counts of the first data set
    546         * @param observed2 array of observed frequency counts of the second data set
    547         * @param alpha significance level of the test
    548         * @return true iff null hypothesis can be rejected with confidence
    549         * 1 - alpha
    550         * @throws DimensionMismatchException the the length of the arrays does not match
    551         * @throws NotPositiveException if any entries in <code>observed1</code> or
    552         * <code>observed2</code> are negative
    553         * @throws ZeroException if either all counts of <code>observed1</code> or
    554         * <code>observed2</code> are zero, or if the count at the same index is zero
    555         * for both arrays
    556         * @throws OutOfRangeException if <code>alpha</code> is not in the range (0, 0.5]
    557         * @throws MaxCountExceededException if an error occurs performing the test
    558         * @since 1.2
    559         */
    560        public boolean chiSquareTestDataSetsComparison(final long[] observed1,
    561                                                       final long[] observed2,
    562                                                       final double alpha)
    563            throws DimensionMismatchException, NotPositiveException,
    564            ZeroException, OutOfRangeException, MaxCountExceededException {
    565
    566            if (alpha <= 0 ||
    567                alpha > 0.5) {
    568                throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUND_SIGNIFICANCE_LEVEL,
    569                                              alpha, 0, 0.5);
    570            }
    571            return chiSquareTestDataSetsComparison(observed1, observed2) < alpha;
    572
    573        }
    574
    575        /**
    576         * Checks to make sure that the input long[][] array is rectangular,
    577         * has at least 2 rows and 2 columns, and has all non-negative entries.
    578         *
    579         * @param in input 2-way table to check
    580         * @throws NullArgumentException if the array is null
    581         * @throws DimensionMismatchException if the array is not valid
    582         * @throws NotPositiveException if the array contains any negative entries
    583         */
    584        private void checkArray(final long[][] in)
    585            throws NullArgumentException, DimensionMismatchException,
    586            NotPositiveException {
    587
    588            if (in.length < 2) {
    589                throw new DimensionMismatchException(in.length, 2);
    590            }
    591
    592            if (in[0].length < 2) {
    593                throw new DimensionMismatchException(in[0].length, 2);
    594            }
    595
    596            MathArrays.checkRectangular(in);
    597            MathArrays.checkNonNegative(in);
    598
    599        }
    600
    601    }