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 }