View Javadoc

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 }