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;
018
019
020 import org.apache.commons.math3.TestUtils;
021 import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
022 import org.apache.commons.math3.util.FastMath;
023 import org.apache.commons.math3.util.Precision;
024 import org.apache.commons.math3.exception.MathIllegalArgumentException;
025 import org.junit.Assert;
026 import org.junit.Test;
027
028 /**
029 * Test cases for the {@link StatUtils} class.
030 * @version $Id: StatUtilsTest.java 1364030 2012-07-21 01:10:04Z erans $
031 */
032
033 public final class StatUtilsTest {
034
035 private double one = 1;
036 private float two = 2;
037 private int three = 3;
038 private double mean = 2;
039 private double sumSq = 18;
040 private double sum = 8;
041 private double var = 0.666666666666666666667;
042 private double min = 1;
043 private double max = 3;
044 private double tolerance = 10E-15;
045 private double nan = Double.NaN;
046
047 /** test stats */
048 @Test
049 public void testStats() {
050 double[] values = new double[] { one, two, two, three };
051 Assert.assertEquals("sum", sum, StatUtils.sum(values), tolerance);
052 Assert.assertEquals("sumsq", sumSq, StatUtils.sumSq(values), tolerance);
053 Assert.assertEquals("var", var, StatUtils.variance(values), tolerance);
054 Assert.assertEquals("var with mean", var, StatUtils.variance(values, mean), tolerance);
055 Assert.assertEquals("mean", mean, StatUtils.mean(values), tolerance);
056 Assert.assertEquals("min", min, StatUtils.min(values), tolerance);
057 Assert.assertEquals("max", max, StatUtils.max(values), tolerance);
058 }
059
060 @Test
061 public void testN0andN1Conditions() {
062 double[] values = new double[0];
063
064 Assert.assertTrue(
065 "Mean of n = 0 set should be NaN",
066 Double.isNaN(StatUtils.mean(values)));
067 Assert.assertTrue(
068 "Variance of n = 0 set should be NaN",
069 Double.isNaN(StatUtils.variance(values)));
070
071 values = new double[] { one };
072
073 Assert.assertTrue(
074 "Mean of n = 1 set should be value of single item n1",
075 StatUtils.mean(values) == one);
076 Assert.assertTrue(
077 "Variance of n = 1 set should be zero",
078 StatUtils.variance(values) == 0);
079 }
080
081 @Test
082 public void testArrayIndexConditions() {
083 double[] values = { 1.0, 2.0, 3.0, 4.0 };
084
085 Assert.assertEquals(
086 "Sum not expected",
087 5.0,
088 StatUtils.sum(values, 1, 2),
089 Double.MIN_VALUE);
090 Assert.assertEquals(
091 "Sum not expected",
092 3.0,
093 StatUtils.sum(values, 0, 2),
094 Double.MIN_VALUE);
095 Assert.assertEquals(
096 "Sum not expected",
097 7.0,
098 StatUtils.sum(values, 2, 2),
099 Double.MIN_VALUE);
100
101 try {
102 StatUtils.sum(values, 2, 3);
103 Assert.fail("Expected RuntimeException");
104 } catch (RuntimeException e) {
105 // expected
106 }
107
108 try {
109 StatUtils.sum(values, -1, 2);
110 Assert.fail("Expected RuntimeException");
111 } catch (RuntimeException e) {
112 // expected
113 }
114
115 }
116
117 @Test
118 public void testSumSq() {
119 double[] x = null;
120
121 // test null
122 try {
123 StatUtils.sumSq(x);
124 Assert.fail("null is not a valid data array.");
125 } catch (MathIllegalArgumentException ex) {
126 // success
127 }
128
129 try {
130 StatUtils.sumSq(x, 0, 4);
131 Assert.fail("null is not a valid data array.");
132 } catch (MathIllegalArgumentException ex) {
133 // success
134 }
135
136 // test empty
137 x = new double[] {};
138 TestUtils.assertEquals(0, StatUtils.sumSq(x), tolerance);
139 TestUtils.assertEquals(0, StatUtils.sumSq(x, 0, 0), tolerance);
140
141 // test one
142 x = new double[] {two};
143 TestUtils.assertEquals(4, StatUtils.sumSq(x), tolerance);
144 TestUtils.assertEquals(4, StatUtils.sumSq(x, 0, 1), tolerance);
145
146 // test many
147 x = new double[] {one, two, two, three};
148 TestUtils.assertEquals(18, StatUtils.sumSq(x), tolerance);
149 TestUtils.assertEquals(8, StatUtils.sumSq(x, 1, 2), tolerance);
150 }
151
152 @Test
153 public void testProduct() {
154 double[] x = null;
155
156 // test null
157 try {
158 StatUtils.product(x);
159 Assert.fail("null is not a valid data array.");
160 } catch (MathIllegalArgumentException ex) {
161 // success
162 }
163
164 try {
165 StatUtils.product(x, 0, 4);
166 Assert.fail("null is not a valid data array.");
167 } catch (MathIllegalArgumentException ex) {
168 // success
169 }
170
171 // test empty
172 x = new double[] {};
173 TestUtils.assertEquals(1, StatUtils.product(x), tolerance);
174 TestUtils.assertEquals(1, StatUtils.product(x, 0, 0), tolerance);
175
176 // test one
177 x = new double[] {two};
178 TestUtils.assertEquals(two, StatUtils.product(x), tolerance);
179 TestUtils.assertEquals(two, StatUtils.product(x, 0, 1), tolerance);
180
181 // test many
182 x = new double[] {one, two, two, three};
183 TestUtils.assertEquals(12, StatUtils.product(x), tolerance);
184 TestUtils.assertEquals(4, StatUtils.product(x, 1, 2), tolerance);
185 }
186
187 @Test
188 public void testSumLog() {
189 double[] x = null;
190
191 // test null
192 try {
193 StatUtils.sumLog(x);
194 Assert.fail("null is not a valid data array.");
195 } catch (MathIllegalArgumentException ex) {
196 // success
197 }
198
199 try {
200 StatUtils.sumLog(x, 0, 4);
201 Assert.fail("null is not a valid data array.");
202 } catch (MathIllegalArgumentException ex) {
203 // success
204 }
205
206 // test empty
207 x = new double[] {};
208 TestUtils.assertEquals(0, StatUtils.sumLog(x), tolerance);
209 TestUtils.assertEquals(0, StatUtils.sumLog(x, 0, 0), tolerance);
210
211 // test one
212 x = new double[] {two};
213 TestUtils.assertEquals(FastMath.log(two), StatUtils.sumLog(x), tolerance);
214 TestUtils.assertEquals(FastMath.log(two), StatUtils.sumLog(x, 0, 1), tolerance);
215
216 // test many
217 x = new double[] {one, two, two, three};
218 TestUtils.assertEquals(FastMath.log(one) + 2.0 * FastMath.log(two) + FastMath.log(three), StatUtils.sumLog(x), tolerance);
219 TestUtils.assertEquals(2.0 * FastMath.log(two), StatUtils.sumLog(x, 1, 2), tolerance);
220 }
221
222 @Test
223 public void testMean() {
224 double[] x = null;
225
226 try {
227 StatUtils.mean(x, 0, 4);
228 Assert.fail("null is not a valid data array.");
229 } catch (MathIllegalArgumentException ex) {
230 // success
231 }
232
233 // test empty
234 x = new double[] {};
235 TestUtils.assertEquals(Double.NaN, StatUtils.mean(x, 0, 0), tolerance);
236
237 // test one
238 x = new double[] {two};
239 TestUtils.assertEquals(two, StatUtils.mean(x, 0, 1), tolerance);
240
241 // test many
242 x = new double[] {one, two, two, three};
243 TestUtils.assertEquals(2.5, StatUtils.mean(x, 2, 2), tolerance);
244 }
245
246 @Test
247 public void testVariance() {
248 double[] x = null;
249
250 try {
251 StatUtils.variance(x, 0, 4);
252 Assert.fail("null is not a valid data array.");
253 } catch (MathIllegalArgumentException ex) {
254 // success
255 }
256
257 // test empty
258 x = new double[] {};
259 TestUtils.assertEquals(Double.NaN, StatUtils.variance(x, 0, 0), tolerance);
260
261 // test one
262 x = new double[] {two};
263 TestUtils.assertEquals(0.0, StatUtils.variance(x, 0, 1), tolerance);
264
265 // test many
266 x = new double[] {one, two, two, three};
267 TestUtils.assertEquals(0.5, StatUtils.variance(x, 2, 2), tolerance);
268
269 // test precomputed mean
270 x = new double[] {one, two, two, three};
271 TestUtils.assertEquals(0.5, StatUtils.variance(x,2.5, 2, 2), tolerance);
272 }
273
274 @Test
275 public void testPopulationVariance() {
276 double[] x = null;
277
278 try {
279 StatUtils.variance(x, 0, 4);
280 Assert.fail("null is not a valid data array.");
281 } catch (MathIllegalArgumentException ex) {
282 // success
283 }
284
285 // test empty
286 x = new double[] {};
287 TestUtils.assertEquals(Double.NaN, StatUtils.populationVariance(x, 0, 0), tolerance);
288
289 // test one
290 x = new double[] {two};
291 TestUtils.assertEquals(0.0, StatUtils.populationVariance(x, 0, 1), tolerance);
292
293 // test many
294 x = new double[] {one, two, two, three};
295 TestUtils.assertEquals(0.25, StatUtils.populationVariance(x, 0, 2), tolerance);
296
297 // test precomputed mean
298 x = new double[] {one, two, two, three};
299 TestUtils.assertEquals(0.25, StatUtils.populationVariance(x, 2.5, 2, 2), tolerance);
300 }
301
302
303 @Test
304 public void testMax() {
305 double[] x = null;
306
307 try {
308 StatUtils.max(x, 0, 4);
309 Assert.fail("null is not a valid data array.");
310 } catch (MathIllegalArgumentException ex) {
311 // success
312 }
313
314 // test empty
315 x = new double[] {};
316 TestUtils.assertEquals(Double.NaN, StatUtils.max(x, 0, 0), tolerance);
317
318 // test one
319 x = new double[] {two};
320 TestUtils.assertEquals(two, StatUtils.max(x, 0, 1), tolerance);
321
322 // test many
323 x = new double[] {one, two, two, three};
324 TestUtils.assertEquals(three, StatUtils.max(x, 1, 3), tolerance);
325
326 // test first nan is ignored
327 x = new double[] {nan, two, three};
328 TestUtils.assertEquals(three, StatUtils.max(x), tolerance);
329
330 // test middle nan is ignored
331 x = new double[] {one, nan, three};
332 TestUtils.assertEquals(three, StatUtils.max(x), tolerance);
333
334 // test last nan is ignored
335 x = new double[] {one, two, nan};
336 TestUtils.assertEquals(two, StatUtils.max(x), tolerance);
337
338 // test all nan returns nan
339 x = new double[] {nan, nan, nan};
340 TestUtils.assertEquals(nan, StatUtils.max(x), tolerance);
341 }
342
343 @Test
344 public void testMin() {
345 double[] x = null;
346
347 try {
348 StatUtils.min(x, 0, 4);
349 Assert.fail("null is not a valid data array.");
350 } catch (MathIllegalArgumentException ex) {
351 // success
352 }
353
354 // test empty
355 x = new double[] {};
356 TestUtils.assertEquals(Double.NaN, StatUtils.min(x, 0, 0), tolerance);
357
358 // test one
359 x = new double[] {two};
360 TestUtils.assertEquals(two, StatUtils.min(x, 0, 1), tolerance);
361
362 // test many
363 x = new double[] {one, two, two, three};
364 TestUtils.assertEquals(two, StatUtils.min(x, 1, 3), tolerance);
365
366 // test first nan is ignored
367 x = new double[] {nan, two, three};
368 TestUtils.assertEquals(two, StatUtils.min(x), tolerance);
369
370 // test middle nan is ignored
371 x = new double[] {one, nan, three};
372 TestUtils.assertEquals(one, StatUtils.min(x), tolerance);
373
374 // test last nan is ignored
375 x = new double[] {one, two, nan};
376 TestUtils.assertEquals(one, StatUtils.min(x), tolerance);
377
378 // test all nan returns nan
379 x = new double[] {nan, nan, nan};
380 TestUtils.assertEquals(nan, StatUtils.min(x), tolerance);
381 }
382
383 @Test
384 public void testPercentile() {
385 double[] x = null;
386
387 // test null
388 try {
389 StatUtils.percentile(x, .25);
390 Assert.fail("null is not a valid data array.");
391 } catch (MathIllegalArgumentException ex) {
392 // success
393 }
394
395 try {
396 StatUtils.percentile(x, 0, 4, 0.25);
397 Assert.fail("null is not a valid data array.");
398 } catch (MathIllegalArgumentException ex) {
399 // success
400 }
401
402 // test empty
403 x = new double[] {};
404 TestUtils.assertEquals(Double.NaN, StatUtils.percentile(x, 25), tolerance);
405 TestUtils.assertEquals(Double.NaN, StatUtils.percentile(x, 0, 0, 25), tolerance);
406
407 // test one
408 x = new double[] {two};
409 TestUtils.assertEquals(two, StatUtils.percentile(x, 25), tolerance);
410 TestUtils.assertEquals(two, StatUtils.percentile(x, 0, 1, 25), tolerance);
411
412 // test many
413 x = new double[] {one, two, two, three};
414 TestUtils.assertEquals(2.5, StatUtils.percentile(x, 70), tolerance);
415 TestUtils.assertEquals(2.5, StatUtils.percentile(x, 1, 3, 62.5), tolerance);
416 }
417
418 @Test
419 public void testDifferenceStats() {
420 double sample1[] = {1d, 2d, 3d, 4d};
421 double sample2[] = {1d, 3d, 4d, 2d};
422 double diff[] = {0d, -1d, -1d, 2d};
423 double small[] = {1d, 4d};
424 double meanDifference = StatUtils.meanDifference(sample1, sample2);
425 Assert.assertEquals(StatUtils.sumDifference(sample1, sample2), StatUtils.sum(diff), tolerance);
426 Assert.assertEquals(meanDifference, StatUtils.mean(diff), tolerance);
427 Assert.assertEquals(StatUtils.varianceDifference(sample1, sample2, meanDifference),
428 StatUtils.variance(diff), tolerance);
429 try {
430 StatUtils.meanDifference(sample1, small);
431 Assert.fail("Expecting MathIllegalArgumentException");
432 } catch (MathIllegalArgumentException ex) {
433 // expected
434 }
435 try {
436 StatUtils.varianceDifference(sample1, small, meanDifference);
437 Assert.fail("Expecting MathIllegalArgumentException");
438 } catch (MathIllegalArgumentException ex) {
439 // expected
440 }
441 try {
442 double[] single = {1.0};
443 StatUtils.varianceDifference(single, single, meanDifference);
444 Assert.fail("Expecting MathIllegalArgumentException");
445 } catch (MathIllegalArgumentException ex) {
446 // expected
447 }
448 }
449
450 @Test
451 public void testGeometricMean() {
452 double[] test = null;
453 try {
454 StatUtils.geometricMean(test);
455 Assert.fail("Expecting MathIllegalArgumentException");
456 } catch (MathIllegalArgumentException ex) {
457 // expected
458 }
459 test = new double[] {2, 4, 6, 8};
460 Assert.assertEquals(FastMath.exp(0.25d * StatUtils.sumLog(test)),
461 StatUtils.geometricMean(test), Double.MIN_VALUE);
462 Assert.assertEquals(FastMath.exp(0.5 * StatUtils.sumLog(test, 0, 2)),
463 StatUtils.geometricMean(test, 0, 2), Double.MIN_VALUE);
464 }
465
466
467 /**
468 * Run the test with the values 50 and 100 and assume standardized values
469 */
470
471 @Test
472 public void testNormalize1() {
473 double sample[] = { 50, 100 };
474 double expectedSample[] = { -25 / Math.sqrt(1250), 25 / Math.sqrt(1250) };
475 double[] out = StatUtils.normalize(sample);
476 for (int i = 0; i < out.length; i++) {
477 Assert.assertTrue(Precision.equals(out[i], expectedSample[i], 1));
478 }
479
480 }
481
482 /**
483 * Run with 77 random values, assuming that the outcome has a mean of 0 and a standard deviation of 1 with a
484 * precision of 1E-10.
485 */
486
487 @Test
488 public void testNormalize2() {
489 // create an sample with 77 values
490 int length = 77;
491 double sample[] = new double[length];
492 for (int i = 0; i < length; i++) {
493 sample[i] = Math.random();
494 }
495 // normalize this sample
496 double standardizedSample[] = StatUtils.normalize(sample);
497
498 DescriptiveStatistics stats = new DescriptiveStatistics();
499 // Add the data from the array
500 for (int i = 0; i < length; i++) {
501 stats.addValue(standardizedSample[i]);
502 }
503 // the calculations do have a limited precision
504 double distance = 1E-10;
505 // check the mean an standard deviation
506 Assert.assertEquals(0.0, stats.getMean(), distance);
507 Assert.assertEquals(1.0, stats.getStandardDeviation(), distance);
508
509 }
510
511 }