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