View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math4.legacy.stat.descriptive.moment;
19  
20  import org.apache.commons.math4.legacy.TestUtils;
21  import org.apache.commons.math4.legacy.exception.NullArgumentException;
22  import org.apache.commons.math4.legacy.stat.StatUtils;
23  import org.junit.Assert;
24  import org.junit.Test;
25  
26  
27  public class SemiVarianceTest {
28  
29      @Test
30      public void testInsufficientData() {
31          double[] nothing = null;
32          SemiVariance sv = new SemiVariance();
33          try {
34              sv.evaluate(nothing);
35              Assert.fail("null is not a valid data array.");
36          } catch (NullArgumentException nae) {
37          }
38  
39          try {
40              sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE);
41              sv.evaluate(nothing);
42              Assert.fail("null is not a valid data array.");
43          } catch (NullArgumentException nae) {
44          }
45          nothing = new double[] {};
46          Assert.assertTrue(Double.isNaN(sv.evaluate(nothing)));
47      }
48  
49      @Test
50      public void testSingleDown() {
51          SemiVariance sv = new SemiVariance();
52          double[] values = { 50.0d };
53          double singletest = sv.evaluate(values);
54          Assert.assertEquals(0.0d, singletest, 0);
55      }
56  
57      @Test
58      public void testSingleUp() {
59          SemiVariance sv = new SemiVariance(SemiVariance.UPSIDE_VARIANCE);
60          double[] values = { 50.0d };
61          double singletest = sv.evaluate(values);
62          Assert.assertEquals(0.0d, singletest, 0);
63      }
64  
65      @Test
66      public void testSample() {
67          final double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d };
68          final int length = values.length;
69          final double mean = StatUtils.mean(values); // 6.333...
70          final SemiVariance sv = new SemiVariance();  // Default bias correction is true
71          final double downsideSemiVariance = sv.evaluate(values); // Downside is the default
72          Assert.assertEquals(TestUtils.sumSquareDev(new double[] {-2d, 2d, 4d, -2d, 3d, 5d}, mean) / (length - 1),
73                  downsideSemiVariance, 1E-14);
74  
75          sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE);
76          final double upsideSemiVariance = sv.evaluate(values);
77          Assert.assertEquals(TestUtils.sumSquareDev(new double[] {22d, 11d, 14d}, mean) / (length - 1),
78                  upsideSemiVariance, 1E-14);
79  
80          // Verify that upper + lower semivariance against the mean sum to variance
81          Assert.assertEquals(StatUtils.variance(values), downsideSemiVariance + upsideSemiVariance, 10e-12);
82      }
83  
84      @Test
85      public void testPopulation() {
86          double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d };
87          SemiVariance sv = new SemiVariance(false);
88  
89          double singletest = sv.evaluate(values);
90          Assert.assertEquals(19.556d, singletest, 0.01d);
91  
92          sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE);
93          singletest = sv.evaluate(values);
94          Assert.assertEquals(36.222d, singletest, 0.01d);
95      }
96  
97      @Test
98      public void testNonMeanCutoffs() {
99          double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d };
100         SemiVariance sv = new SemiVariance(false); // Turn off bias correction - use df = length
101 
102         double singletest = sv.evaluate(values, 1.0d, SemiVariance.DOWNSIDE_VARIANCE, false, 0, values.length);
103         Assert.assertEquals(TestUtils.sumSquareDev(new double[] { -2d, -2d }, 1.0d) / values.length,
104                 singletest, 0.01d);
105 
106         singletest = sv.evaluate(values, 3.0d, SemiVariance.UPSIDE_VARIANCE, false, 0, values.length);
107         Assert.assertEquals(TestUtils.sumSquareDev(new double[] { 4d, 22d, 11d, 14d, 5d }, 3.0d) / values.length, singletest,
108                 0.01d);
109     }
110 
111     /**
112      * Check that the lower + upper semivariance against the mean sum to the
113      * variance.
114      */
115     @Test
116     public void testVarianceDecompMeanCutoff() {
117         double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d };
118         double variance = StatUtils.variance(values);
119         SemiVariance sv = new SemiVariance(true); // Bias corrected
120         sv.setVarianceDirection(SemiVariance.DOWNSIDE_VARIANCE);
121         final double lower = sv.evaluate(values);
122         sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE);
123         final double upper = sv.evaluate(values);
124         Assert.assertEquals(variance, lower + upper, 10e-12);
125     }
126 
127     /**
128      * Check that upper and lower semivariances against a cutoff sum to the sum
129      * of squared deviations of the full set of values against the cutoff
130      * divided by df = length - 1 (assuming bias-corrected).
131      */
132     @Test
133     public void testVarianceDecompNonMeanCutoff() {
134         double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d };
135         double target = 0;
136         double totalSumOfSquares = TestUtils.sumSquareDev(values, target);
137         SemiVariance sv = new SemiVariance(true); // Bias corrected
138         sv.setVarianceDirection(SemiVariance.DOWNSIDE_VARIANCE);
139         double lower = sv.evaluate(values, target);
140         sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE);
141         double upper = sv.evaluate(values, target);
142         Assert.assertEquals(totalSumOfSquares / (values.length - 1), lower + upper, 10e-12);
143     }
144 
145     @Test
146     public void testNoVariance() {
147         final double[] values = {100d, 100d, 100d, 100d};
148         SemiVariance sv = new SemiVariance();
149         Assert.assertEquals(0, sv.evaluate(values), 10E-12);
150         Assert.assertEquals(0, sv.evaluate(values, 100d), 10E-12);
151         Assert.assertEquals(0, sv.evaluate(values, 100d, SemiVariance.UPSIDE_VARIANCE, false, 0, values.length), 10E-12);
152     }
153 }