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.math3.stat.correlation; 019 020 import org.apache.commons.math3.exception.DimensionMismatchException; 021 import org.apache.commons.math3.exception.MathIllegalArgumentException; 022 import org.apache.commons.math3.exception.util.LocalizedFormats; 023 import org.apache.commons.math3.linear.BlockRealMatrix; 024 import org.apache.commons.math3.linear.RealMatrix; 025 import org.apache.commons.math3.stat.ranking.NaturalRanking; 026 import org.apache.commons.math3.stat.ranking.RankingAlgorithm; 027 028 /** 029 * <p>Spearman's rank correlation. This implementation performs a rank 030 * transformation on the input data and then computes {@link PearsonsCorrelation} 031 * on the ranked data.</p> 032 * 033 * <p>By default, ranks are computed using {@link NaturalRanking} with default 034 * strategies for handling NaNs and ties in the data (NaNs maximal, ties averaged). 035 * The ranking algorithm can be set using a constructor argument.</p> 036 * 037 * @since 2.0 038 * @version $Id: SpearmansCorrelation.java 1422313 2012-12-15 18:53:41Z psteitz $ 039 */ 040 041 public class SpearmansCorrelation { 042 043 /** Input data */ 044 private final RealMatrix data; 045 046 /** Ranking algorithm */ 047 private final RankingAlgorithm rankingAlgorithm; 048 049 /** Rank correlation */ 050 private final PearsonsCorrelation rankCorrelation; 051 052 /** 053 * Create a SpearmansCorrelation without data. 054 */ 055 public SpearmansCorrelation() { 056 this(new NaturalRanking()); 057 } 058 059 /** 060 * Create a SpearmansCorrelation with the given ranking algorithm. 061 * 062 * @param rankingAlgorithm ranking algorithm 063 * @since 3.1 064 */ 065 public SpearmansCorrelation(final RankingAlgorithm rankingAlgorithm) { 066 data = null; 067 this.rankingAlgorithm = rankingAlgorithm; 068 rankCorrelation = null; 069 } 070 071 /** 072 * Create a SpearmansCorrelation from the given data matrix. 073 * 074 * @param dataMatrix matrix of data with columns representing 075 * variables to correlate 076 */ 077 public SpearmansCorrelation(final RealMatrix dataMatrix) { 078 this(dataMatrix, new NaturalRanking()); 079 } 080 081 /** 082 * Create a SpearmansCorrelation with the given input data matrix 083 * and ranking algorithm. 084 * 085 * @param dataMatrix matrix of data with columns representing 086 * variables to correlate 087 * @param rankingAlgorithm ranking algorithm 088 */ 089 public SpearmansCorrelation(final RealMatrix dataMatrix, final RankingAlgorithm rankingAlgorithm) { 090 this.data = dataMatrix.copy(); 091 this.rankingAlgorithm = rankingAlgorithm; 092 rankTransform(data); 093 rankCorrelation = new PearsonsCorrelation(data); 094 } 095 096 /** 097 * Calculate the Spearman Rank Correlation Matrix. 098 * 099 * @return Spearman Rank Correlation Matrix 100 */ 101 public RealMatrix getCorrelationMatrix() { 102 return rankCorrelation.getCorrelationMatrix(); 103 } 104 105 /** 106 * Returns a {@link PearsonsCorrelation} instance constructed from the 107 * ranked input data. That is, 108 * <code>new SpearmansCorrelation(matrix).getRankCorrelation()</code> 109 * is equivalent to 110 * <code>new PearsonsCorrelation(rankTransform(matrix))</code> where 111 * <code>rankTransform(matrix)</code> is the result of applying the 112 * configured <code>RankingAlgorithm</code> to each of the columns of 113 * <code>matrix.</code> 114 * 115 * @return PearsonsCorrelation among ranked column data 116 */ 117 public PearsonsCorrelation getRankCorrelation() { 118 return rankCorrelation; 119 } 120 121 /** 122 * Computes the Spearman's rank correlation matrix for the columns of the 123 * input matrix. 124 * 125 * @param matrix matrix with columns representing variables to correlate 126 * @return correlation matrix 127 */ 128 public RealMatrix computeCorrelationMatrix(RealMatrix matrix) { 129 RealMatrix matrixCopy = matrix.copy(); 130 rankTransform(matrixCopy); 131 return new PearsonsCorrelation().computeCorrelationMatrix(matrixCopy); 132 } 133 134 /** 135 * Computes the Spearman's rank correlation matrix for the columns of the 136 * input rectangular array. The columns of the array represent values 137 * of variables to be correlated. 138 * 139 * @param matrix matrix with columns representing variables to correlate 140 * @return correlation matrix 141 */ 142 public RealMatrix computeCorrelationMatrix(double[][] matrix) { 143 return computeCorrelationMatrix(new BlockRealMatrix(matrix)); 144 } 145 146 /** 147 * Computes the Spearman's rank correlation coefficient between the two arrays. 148 * 149 * @param xArray first data array 150 * @param yArray second data array 151 * @return Returns Spearman's rank correlation coefficient for the two arrays 152 * @throws DimensionMismatchException if the arrays lengths do not match 153 * @throws MathIllegalArgumentException if the array length is less than 2 154 */ 155 public double correlation(final double[] xArray, final double[] yArray) { 156 if (xArray.length != yArray.length) { 157 throw new DimensionMismatchException(xArray.length, yArray.length); 158 } else if (xArray.length < 2) { 159 throw new MathIllegalArgumentException(LocalizedFormats.INSUFFICIENT_DIMENSION, 160 xArray.length, 2); 161 } else { 162 return new PearsonsCorrelation().correlation(rankingAlgorithm.rank(xArray), 163 rankingAlgorithm.rank(yArray)); 164 } 165 } 166 167 /** 168 * Applies rank transform to each of the columns of <code>matrix</code> 169 * using the current <code>rankingAlgorithm</code> 170 * 171 * @param matrix matrix to transform 172 */ 173 private void rankTransform(RealMatrix matrix) { 174 for (int i = 0; i < matrix.getColumnDimension(); i++) { 175 matrix.setColumn(i, rankingAlgorithm.rank(matrix.getColumn(i))); 176 } 177 } 178 }