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