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    *      https://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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.stat.correlation;
23  
24  import java.util.Arrays;
25  
26  import org.hipparchus.UnitTestUtils;
27  import org.hipparchus.linear.BlockRealMatrix;
28  import org.hipparchus.linear.RealMatrix;
29  import org.hipparchus.random.RandomGenerator;
30  import org.hipparchus.random.Well1024a;
31  import org.junit.Assert;
32  import org.junit.Before;
33  import org.junit.Test;
34  
35  /**
36   * Test cases for Kendall's Tau rank correlation.
37   */
38  public class KendallsCorrelationTest extends PearsonsCorrelationTest {
39  
40      private KendallsCorrelation correlation;
41  
42      @Before
43      public void setUp() {
44          correlation = new KendallsCorrelation();
45      }
46  
47      /**
48       * Test Longley dataset against R.
49       */
50      @Override
51      @Test
52      public void testLongly() {
53          RealMatrix matrix = createRealMatrix(longleyData, 16, 7);
54          KendallsCorrelation corrInstance = new KendallsCorrelation(matrix);
55          RealMatrix correlationMatrix = corrInstance.getCorrelationMatrix();
56          double[] rData = new double[] {
57                  1, 0.9166666666666666, 0.9333333333333332, 0.3666666666666666, 0.05, 0.8999999999999999,
58                  0.8999999999999999, 0.9166666666666666, 1, 0.9833333333333333, 0.45, 0.03333333333333333,
59                  0.9833333333333333, 0.9833333333333333, 0.9333333333333332, 0.9833333333333333, 1,
60                  0.4333333333333333, 0.05, 0.9666666666666666, 0.9666666666666666, 0.3666666666666666,
61                  0.45, 0.4333333333333333, 1, -0.2166666666666666, 0.4666666666666666, 0.4666666666666666, 0.05,
62                  0.03333333333333333, 0.05, -0.2166666666666666, 1, 0.05, 0.05, 0.8999999999999999, 0.9833333333333333,
63                  0.9666666666666666, 0.4666666666666666, 0.05, 1, 0.9999999999999999, 0.8999999999999999,
64                  0.9833333333333333, 0.9666666666666666, 0.4666666666666666, 0.05, 0.9999999999999999, 1
65          };
66          UnitTestUtils.assertEquals("Kendall's correlation matrix", createRealMatrix(rData, 7, 7), correlationMatrix, 10E-15);
67      }
68  
69      /**
70       * Test R swiss fertility dataset.
71       */
72      @Test
73      public void testSwiss() {
74          RealMatrix matrix = createRealMatrix(swissData, 47, 5);
75          KendallsCorrelation corrInstance = new KendallsCorrelation(matrix);
76          RealMatrix correlationMatrix = corrInstance.getCorrelationMatrix();
77          double[] rData = new double[] {
78                  1, 0.1795465254708308, -0.4762437404200669, -0.3306111613580587, 0.2453703703703704,
79                  0.1795465254708308, 1, -0.4505221560842292, -0.4761645631778491, 0.2054604569820847,
80                  -0.4762437404200669, -0.4505221560842292, 1, 0.528943683925829, -0.3212755391722673,
81                  -0.3306111613580587, -0.4761645631778491, 0.528943683925829, 1, -0.08479652265379604,
82                  0.2453703703703704, 0.2054604569820847, -0.3212755391722673, -0.08479652265379604, 1
83          };
84          UnitTestUtils.assertEquals("Kendall's correlation matrix", createRealMatrix(rData, 5, 5), correlationMatrix, 10E-15);
85      }
86  
87      @Test
88      public void testSimpleOrdered() {
89          final int length = 10;
90          final double[] xArray = new double[length];
91          final double[] yArray = new double[length];
92          for (int i = 0; i < length; i++) {
93              xArray[i] = i;
94              yArray[i] = i;
95          }
96          Assert.assertEquals(1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE);
97      }
98  
99      @Test
100     public void testSimpleReversed() {
101         final int length = 10;
102         final double[] xArray = new double[length];
103         final double[] yArray = new double[length];
104         for (int i = 0; i < length; i++) {
105             xArray[length - i - 1] = i;
106             yArray[i] = i;
107         }
108         Assert.assertEquals(-1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE);
109     }
110 
111     @Test
112     public void testSimpleOrderedPowerOf2() {
113         final int length = 16;
114         final double[] xArray = new double[length];
115         final double[] yArray = new double[length];
116         for (int i = 0; i < length; i++) {
117             xArray[i] = i;
118             yArray[i] = i;
119         }
120         Assert.assertEquals(1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE);
121     }
122 
123     @Test
124     public void testSimpleReversedPowerOf2() {
125         final int length = 16;
126         final double[] xArray = new double[length];
127         final double[] yArray = new double[length];
128         for (int i = 0; i < length; i++) {
129             xArray[length - i - 1] = i;
130             yArray[i] = i;
131         }
132         Assert.assertEquals(-1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE);
133     }
134 
135     @Test
136     public void testSimpleJumble() {
137         //                                     A    B    C    D
138         final double[] xArray = new double[] {1.0, 2.0, 3.0, 4.0};
139         final double[] yArray = new double[] {1.0, 3.0, 2.0, 4.0};
140 
141         // 6 pairs: (A,B) (A,C) (A,D) (B,C) (B,D) (C,D)
142         // (B,C) is discordant, the other 5 are concordant
143 
144         Assert.assertEquals((5 - 1) / (double) 6,
145                 correlation.correlation(xArray, yArray),
146                 Double.MIN_VALUE);
147     }
148 
149     @Test
150     public void testBalancedJumble() {
151         //                                     A    B    C    D
152         final double[] xArray = new double[] {1.0, 2.0, 3.0, 4.0};
153         final double[] yArray = new double[] {1.0, 4.0, 3.0, 2.0};
154 
155         // 6 pairs: (A,B) (A,C) (A,D) (B,C) (B,D) (C,D)
156         // (A,B) (A,C), (A,D) are concordant, the other 3 are discordant
157 
158         Assert.assertEquals(0.0,
159                 correlation.correlation(xArray, yArray),
160                 Double.MIN_VALUE);
161     }
162 
163     @Test
164     public void testOrderedTies() {
165         final int length = 10;
166         final double[] xArray = new double[length];
167         final double[] yArray = new double[length];
168         for (int i = 0; i < length; i++) {
169             xArray[i] = i / 2;
170             yArray[i] = i / 2;
171         }
172         // 5 pairs of points that are tied in both values.
173         // 16 + 12 + 8 + 4 = 40 concordant
174         // (40 - 0) / Math.sqrt((45 - 5) * (45 - 5)) = 1
175         Assert.assertEquals(1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE);
176     }
177 
178 
179     @Test
180     public void testAllTiesInBoth() {
181         final int length = 10;
182         final double[] xArray = new double[length];
183         final double[] yArray = new double[length];
184         Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0);
185     }
186 
187     @Test
188     public void testAllTiesInX() {
189         final int length = 10;
190         final double[] xArray = new double[length];
191         final double[] yArray = new double[length];
192         for (int i = 0; i < length; i++) {
193             xArray[i] = i;
194         }
195         Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0);
196     }
197 
198     @Test
199     public void testAllTiesInY() {
200         final int length = 10;
201         final double[] xArray = new double[length];
202         final double[] yArray = new double[length];
203         for (int i = 0; i < length; i++) {
204             yArray[i] = i;
205         }
206         Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0);
207     }
208 
209     @Test
210     public void testSingleElement() {
211         final int length = 1;
212         final double[] xArray = new double[length];
213         final double[] yArray = new double[length];
214         Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0);
215     }
216 
217     @Test
218     public void testTwoElements() {
219         final double[] xArray = new double[] {2.0, 1.0};
220         final double[] yArray = new double[] {1.0, 2.0};
221         Assert.assertEquals(-1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE);
222     }
223 
224     @Test
225     public void test2dDoubleArray() {
226         final double[][] input = new double[][] {
227                 new double[] {2.0, 1.0, 2.0},
228                 new double[] {1.0, 2.0, 1.0},
229                 new double[] {0.0, 0.0, 0.0}
230         };
231 
232         final double[][] expected = new double[][] {
233                 new double[] {1.0, 1.0 / 3.0, 1.0},
234                 new double[] {1.0 / 3.0, 1.0, 1.0 / 3.0},
235                 new double[] {1.0, 1.0 / 3.0, 1.0}};
236 
237         Assert.assertEquals(correlation.computeCorrelationMatrix(input),
238                 new BlockRealMatrix(expected));
239 
240     }
241 
242     @Test
243     public void testBlockMatrix() {
244         final double[][] input = new double[][] {
245                 new double[] {2.0, 1.0, 2.0},
246                 new double[] {1.0, 2.0, 1.0},
247                 new double[] {0.0, 0.0, 0.0}
248         };
249 
250         final double[][] expected = new double[][] {
251                 new double[] {1.0, 1.0 / 3.0, 1.0},
252                 new double[] {1.0 / 3.0, 1.0, 1.0 / 3.0},
253                 new double[] {1.0, 1.0 / 3.0, 1.0}};
254 
255         Assert.assertEquals(
256                 correlation.computeCorrelationMatrix(new BlockRealMatrix(input)),
257                 new BlockRealMatrix(expected));
258     }
259 
260     @Test
261     public void testLargeArray() {
262         // test integer overflow detected in MATH-1068
263         double[] xArray = new double[100000];
264         Arrays.fill(xArray, 0, 2500, 1.0);
265 
266         Assert.assertEquals(1.0, correlation.correlation(xArray, xArray), 1e-6);
267     }
268 
269     @Test
270     public void testMath1277() {
271         // example that led to a correlation coefficient outside of [-1, 1]
272         // due to a bug reported in MATH-1277
273         RandomGenerator rng = new Well1024a(0);
274         double[] xArray = new double[120000];
275         double[] yArray = new double[120000];
276         for (int i = 0; i < xArray.length; ++i) {
277             xArray[i] =  rng.nextDouble();
278         }
279         for (int i = 0; i < yArray.length; ++i) {
280             yArray[i] =  rng.nextDouble();
281         }
282         double coefficient = correlation.correlation(xArray, yArray);
283         Assert.assertTrue(1.0 >= coefficient && -1.0 <= coefficient);
284     }
285 }