001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.math.stat.correlation; 019 020 import org.apache.commons.math.MathRuntimeException; 021 import org.apache.commons.math.exception.util.LocalizedFormats; 022 import org.apache.commons.math.linear.BlockRealMatrix; 023 import org.apache.commons.math.linear.RealMatrix; 024 import org.apache.commons.math.stat.ranking.NaturalRanking; 025 import org.apache.commons.math.stat.ranking.RankingAlgorithm; 026 027 /** 028 * <p>Spearman's rank correlation. This implementation performs a rank 029 * transformation on the input data and then computes {@link PearsonsCorrelation} 030 * on the ranked data.</p> 031 * 032 * <p>By default, ranks are computed using {@link NaturalRanking} with default 033 * strategies for handling NaNs and ties in the data (NaNs maximal, ties averaged). 034 * The ranking algorithm can be set using a constructor argument.</p> 035 * 036 * @since 2.0 037 * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 ao??t 2010) $ 038 */ 039 040 public class SpearmansCorrelation { 041 042 /** Input data */ 043 private final RealMatrix data; 044 045 /** Ranking algorithm */ 046 private final RankingAlgorithm rankingAlgorithm; 047 048 /** Rank correlation */ 049 private final PearsonsCorrelation rankCorrelation; 050 051 /** 052 * Create a SpearmansCorrelation with the given input data matrix 053 * and ranking algorithm. 054 * 055 * @param dataMatrix matrix of data with columns representing 056 * variables to correlate 057 * @param rankingAlgorithm ranking algorithm 058 */ 059 public SpearmansCorrelation(final RealMatrix dataMatrix, final RankingAlgorithm rankingAlgorithm) { 060 this.data = dataMatrix.copy(); 061 this.rankingAlgorithm = rankingAlgorithm; 062 rankTransform(data); 063 rankCorrelation = new PearsonsCorrelation(data); 064 } 065 066 /** 067 * Create a SpearmansCorrelation from the given data matrix. 068 * 069 * @param dataMatrix matrix of data with columns representing 070 * variables to correlate 071 */ 072 public SpearmansCorrelation(final RealMatrix dataMatrix) { 073 this(dataMatrix, new NaturalRanking()); 074 } 075 076 /** 077 * Create a SpearmansCorrelation without data. 078 */ 079 public SpearmansCorrelation() { 080 data = null; 081 this.rankingAlgorithm = new NaturalRanking(); 082 rankCorrelation = null; 083 } 084 085 /** 086 * Calculate the Spearman Rank Correlation Matrix. 087 * 088 * @return Spearman Rank Correlation Matrix 089 */ 090 public RealMatrix getCorrelationMatrix() { 091 return rankCorrelation.getCorrelationMatrix(); 092 } 093 094 /** 095 * Returns a {@link PearsonsCorrelation} instance constructed from the 096 * ranked input data. That is, 097 * <code>new SpearmansCorrelation(matrix).getRankCorrelation()</code> 098 * is equivalent to 099 * <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 }