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 18package org.apache.commons.math.stat.correlation; 19 20import org.apache.commons.math.MathRuntimeException; 21import org.apache.commons.math.exception.util.LocalizedFormats; 22import org.apache.commons.math.linear.BlockRealMatrix; 23import org.apache.commons.math.linear.RealMatrix; 24import org.apache.commons.math.stat.ranking.NaturalRanking; 25import org.apache.commons.math.stat.ranking.RankingAlgorithm; 26 27/** 28 * <p>Spearman's rank correlation. This implementation performs a rank 29 * transformation on the input data and then computes {@link PearsonsCorrelation} 30 * on the ranked data.</p> 31 * 32 * <p>By default, ranks are computed using {@link NaturalRanking} with default 33 * strategies for handling NaNs and ties in the data (NaNs maximal, ties averaged). 34 * The ranking algorithm can be set using a constructor argument.</p> 35 * 36 * @since 2.0 37 * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 août 2010) $ 38 */ 39 40public class SpearmansCorrelation { 41 42 /** Input data */ 43 private final RealMatrix data; 44 45 /** Ranking algorithm */ 46 private final RankingAlgorithm rankingAlgorithm; 47 48 /** Rank correlation */ 49 private final PearsonsCorrelation rankCorrelation; 50 51 /** 52 * Create a SpearmansCorrelation with the given input data matrix 53 * and ranking algorithm. 54 * 55 * @param dataMatrix matrix of data with columns representing 56 * variables to correlate 57 * @param rankingAlgorithm ranking algorithm 58 */ 59 public SpearmansCorrelation(final RealMatrix dataMatrix, final RankingAlgorithm rankingAlgorithm) { 60 this.data = dataMatrix.copy(); 61 this.rankingAlgorithm = rankingAlgorithm; 62 rankTransform(data); 63 rankCorrelation = new PearsonsCorrelation(data); 64 } 65 66 /** 67 * Create a SpearmansCorrelation from the given data matrix. 68 * 69 * @param dataMatrix matrix of data with columns representing 70 * variables to correlate 71 */ 72 public SpearmansCorrelation(final RealMatrix dataMatrix) { 73 this(dataMatrix, new NaturalRanking()); 74 } 75 76 /** 77 * Create a SpearmansCorrelation without data. 78 */ 79 public SpearmansCorrelation() { 80 data = null; 81 this.rankingAlgorithm = new NaturalRanking(); 82 rankCorrelation = null; 83 } 84 85 /** 86 * Calculate the Spearman Rank Correlation Matrix. 87 * 88 * @return Spearman Rank Correlation Matrix 89 */ 90 public RealMatrix getCorrelationMatrix() { 91 return rankCorrelation.getCorrelationMatrix(); 92 } 93 94 /** 95 * Returns a {@link PearsonsCorrelation} instance constructed from the 96 * ranked input data. That is, 97 * <code>new SpearmansCorrelation(matrix).getRankCorrelation()</code> 98 * is equivalent to 99 * <code>new PearsonsCorrelation(rankTransform(matrix))</code> where 100 * <code>rankTransform(matrix)</code> is the result of applying the 101 * configured <code>RankingAlgorithm</code> to each of the columns of 102 * <code>matrix.</code> 103 * 104 * @return PearsonsCorrelation among ranked column data 105 */ 106 public PearsonsCorrelation getRankCorrelation() { 107 return rankCorrelation; 108 } 109 110 /** 111 * Computes the Spearman's rank correlation matrix for the columns of the 112 * input matrix. 113 * 114 * @param matrix matrix with columns representing variables to correlate 115 * @return correlation matrix 116 */ 117 public RealMatrix computeCorrelationMatrix(RealMatrix matrix) { 118 RealMatrix matrixCopy = matrix.copy(); 119 rankTransform(matrixCopy); 120 return new PearsonsCorrelation().computeCorrelationMatrix(matrixCopy); 121 } 122 123 /** 124 * Computes the Spearman's rank correlation matrix for the columns of the 125 * input rectangular array. The columns of the array represent values 126 * of variables to be correlated. 127 * 128 * @param matrix matrix with columns representing variables to correlate 129 * @return correlation matrix 130 */ 131 public RealMatrix computeCorrelationMatrix(double[][] matrix) { 132 return computeCorrelationMatrix(new BlockRealMatrix(matrix)); 133 } 134 135 /** 136 * Computes the Spearman's rank correlation coefficient between the two arrays. 137 * 138 * </p>Throws IllegalArgumentException if the arrays do not have the same length 139 * or their common length is less than 2</p> 140 * 141 * @param xArray first data array 142 * @param yArray second data array 143 * @return Returns Spearman's rank correlation coefficient for the two arrays 144 * @throws IllegalArgumentException if the arrays lengths do not match or 145 * there is insufficient data 146 */ 147 public double correlation(final double[] xArray, final double[] yArray) 148 throws IllegalArgumentException { 149 if (xArray.length != yArray.length) { 150 throw MathRuntimeException.createIllegalArgumentException( 151 LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, xArray.length, yArray.length); 152 } else if (xArray.length < 2) { 153 throw MathRuntimeException.createIllegalArgumentException( 154 LocalizedFormats.INSUFFICIENT_DIMENSION, xArray.length, 2); 155 } else { 156 return new PearsonsCorrelation().correlation(rankingAlgorithm.rank(xArray), 157 rankingAlgorithm.rank(yArray)); 158 } 159 } 160 161 /** 162 * Applies rank transform to each of the columns of <code>matrix</code> 163 * using the current <code>rankingAlgorithm</code> 164 * 165 * @param matrix matrix to transform 166 */ 167 private void rankTransform(RealMatrix matrix) { 168 for (int i = 0; i < matrix.getColumnDimension(); i++) { 169 matrix.setColumn(i, rankingAlgorithm.rank(matrix.getColumn(i))); 170 } 171 } 172} 173