KendallsCorrelation { public double correlation(final double[] xArray, final double[] yArray) throws DimensionMismatchException { if (xArray.length != yArray.length) { throw new DimensionMismatchException(xArray.length, yArray.length); } final int n = xArray.length; final long numPairs = sum(n - 1); @SuppressWarnings("unchecked") Pair<Double, Double>[] pairs = new Pair[n]; for (int i = 0; i < n; i++) { pairs[i] = new Pair<Double, Double>(xArray[i], yArray[i]); } Arrays.sort(pairs, new Comparator<Pair<Double, Double>>() { public int compare(Pair<Double, Double> pair1, Pair<Double, Double> pair2) { int compareFirst = pair1.getFirst().compareTo(pair2.getFirst()); return compareFirst != 0 ? compareFirst : pair1.getSecond().compareTo(pair2.getSecond()); } }); long tiedXPairs = 0; long tiedXYPairs = 0; long consecutiveXTies = 1; long consecutiveXYTies = 1; Pair<Double, Double> prev = pairs[0]; for (int i = 1; i < n; i++) { final Pair<Double, Double> curr = pairs[i]; if (curr.getFirst().equals(prev.getFirst())) { consecutiveXTies++; if (curr.getSecond().equals(prev.getSecond())) { consecutiveXYTies++; } else { tiedXYPairs += sum(consecutiveXYTies - 1); consecutiveXYTies = 1; } } else { tiedXPairs += sum(consecutiveXTies - 1); consecutiveXTies = 1; tiedXYPairs += sum(consecutiveXYTies - 1); consecutiveXYTies = 1; } prev = curr; } tiedXPairs += sum(consecutiveXTies - 1); tiedXYPairs += sum(consecutiveXYTies - 1); int swaps = 0; @SuppressWarnings("unchecked") Pair<Double, Double>[] pairsDestination = new Pair[n]; for (int segmentSize = 1; segmentSize < n; segmentSize <<= 1) { for (int offset = 0; offset < n; offset += 2 * segmentSize) { int i = offset; final int iEnd = FastMath.min(i + segmentSize, n); int j = iEnd; final int jEnd = FastMath.min(j + segmentSize, n); int copyLocation = offset; while (i < iEnd || j < jEnd) { if (i < iEnd) { if (j < jEnd) { if (pairs[i].getSecond().compareTo(pairs[j].getSecond()) <= 0) { pairsDestination[copyLocation] = pairs[i]; i++; } else { pairsDestination[copyLocation] = pairs[j]; j++; swaps += iEnd - i; } } else { pairsDestination[copyLocation] = pairs[i]; i++; } } else { pairsDestination[copyLocation] = pairs[j]; j++; } copyLocation++; } } final Pair<Double, Double>[] pairsTemp = pairs; pairs = pairsDestination; pairsDestination = pairsTemp; } long tiedYPairs = 0; long consecutiveYTies = 1; prev = pairs[0]; for (int i = 1; i < n; i++) { final Pair<Double, Double> curr = pairs[i]; if (curr.getSecond().equals(prev.getSecond())) { consecutiveYTies++; } else { tiedYPairs += sum(consecutiveYTies - 1); consecutiveYTies = 1; } prev = curr; } tiedYPairs += sum(consecutiveYTies - 1); final long concordantMinusDiscordant = numPairs - tiedXPairs - tiedYPairs + tiedXYPairs - 2 * swaps; final double nonTiedPairsMultiplied = (numPairs - tiedXPairs) * (double) (numPairs - tiedYPairs); return concordantMinusDiscordant / FastMath.sqrt(nonTiedPairsMultiplied); } KendallsCorrelation();  KendallsCorrelation(double[][] data);  KendallsCorrelation(RealMatrix matrix); RealMatrix getCorrelationMatrix(); RealMatrix computeCorrelationMatrix(final RealMatrix matrix); RealMatrix computeCorrelationMatrix(final double[][] matrix); double correlation(final double[] xArray, final double[] yArray);  }
@Test public void testSimpleOrdered() { final int length = 10; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { xArray[i] = i; yArray[i] = i; } Assert.assertEquals(1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testSimpleReversed() { final int length = 10; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { xArray[length - i - 1] = i; yArray[i] = i; } Assert.assertEquals(-1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testSimpleOrderedPowerOf2() { final int length = 16; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { xArray[i] = i; yArray[i] = i; } Assert.assertEquals(1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testSimpleReversedPowerOf2() { final int length = 16; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { xArray[length - i - 1] = i; yArray[i] = i; } Assert.assertEquals(-1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testSimpleJumble() { final double[] xArray = new double[] {1.0, 2.0, 3.0, 4.0}; final double[] yArray = new double[] {1.0, 3.0, 2.0, 4.0}; Assert.assertEquals((5 - 1) / (double) 6, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testBalancedJumble() { final double[] xArray = new double[] {1.0, 2.0, 3.0, 4.0}; final double[] yArray = new double[] {1.0, 4.0, 3.0, 2.0}; Assert.assertEquals(0.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testOrderedTies() { final int length = 10; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { xArray[i] = i / 2; yArray[i] = i / 2; } Assert.assertEquals(1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testAllTiesInBoth() { final int length = 10; final double[] xArray = new double[length]; final double[] yArray = new double[length]; Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0); }
@Test public void testAllTiesInX() { final int length = 10; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { xArray[i] = i; } Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0); }
@Test public void testAllTiesInY() { final int length = 10; final double[] xArray = new double[length]; final double[] yArray = new double[length]; for (int i = 0; i < length; i++) { yArray[i] = i; } Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0); }
@Test public void testSingleElement() { final int length = 1; final double[] xArray = new double[length]; final double[] yArray = new double[length]; Assert.assertEquals(Double.NaN, correlation.correlation(xArray, yArray), 0); }
@Test public void testTwoElements() { final double[] xArray = new double[] {2.0, 1.0}; final double[] yArray = new double[] {1.0, 2.0}; Assert.assertEquals(-1.0, correlation.correlation(xArray, yArray), Double.MIN_VALUE); }
@Test public void testLargeArray() { double[] xArray = new double[100000]; Arrays.fill(xArray, 0, 2500, 1.0); Assert.assertEquals(1.0, correlation.correlation(xArray, xArray), 1e-6); }