Home | History | Annotate | Download | only in correlation
      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.exception.util.LocalizedFormats;
     22 import org.apache.commons.math.linear.BlockRealMatrix;
     23 import org.apache.commons.math.linear.RealMatrix;
     24 import org.apache.commons.math.stat.ranking.NaturalRanking;
     25 import org.apache.commons.math.stat.ranking.RankingAlgorithm;
     26 
     27 /**
     28  * <p>Spearman's rank correlation. This implementation performs a rank
     29  * transformation on the input data and then computes {@link PearsonsCorrelation}
     30  * on the ranked data.</p>
     31  *
     32  * <p>By default, ranks are computed using {@link NaturalRanking} with default
     33  * strategies for handling NaNs and ties in the data (NaNs maximal, ties averaged).
     34  * The ranking algorithm can be set using a constructor argument.</p>
     35  *
     36  * @since 2.0
     37  * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 aot 2010) $
     38  */
     39 
     40 public class SpearmansCorrelation {
     41 
     42     /** Input data */
     43     private final RealMatrix data;
     44 
     45     /** Ranking algorithm  */
     46     private final RankingAlgorithm rankingAlgorithm;
     47 
     48     /** Rank correlation */
     49     private final PearsonsCorrelation rankCorrelation;
     50 
     51     /**
     52      * Create a SpearmansCorrelation with the given input data matrix
     53      * and ranking algorithm.
     54      *
     55      * @param dataMatrix matrix of data with columns representing
     56      * variables to correlate
     57      * @param rankingAlgorithm ranking algorithm
     58      */
     59     public SpearmansCorrelation(final RealMatrix dataMatrix, final RankingAlgorithm rankingAlgorithm) {
     60         this.data = dataMatrix.copy();
     61         this.rankingAlgorithm = rankingAlgorithm;
     62         rankTransform(data);
     63         rankCorrelation = new PearsonsCorrelation(data);
     64     }
     65 
     66     /**
     67      * Create a SpearmansCorrelation from the given data matrix.
     68      *
     69      * @param dataMatrix matrix of data with columns representing
     70      * variables to correlate
     71      */
     72     public SpearmansCorrelation(final RealMatrix dataMatrix) {
     73         this(dataMatrix, new NaturalRanking());
     74     }
     75 
     76     /**
     77      * Create a SpearmansCorrelation without data.
     78      */
     79     public SpearmansCorrelation() {
     80         data = null;
     81         this.rankingAlgorithm = new NaturalRanking();
     82         rankCorrelation = null;
     83     }
     84 
     85     /**
     86      * Calculate the Spearman Rank Correlation Matrix.
     87      *
     88      * @return Spearman Rank Correlation Matrix
     89      */
     90     public RealMatrix getCorrelationMatrix() {
     91         return rankCorrelation.getCorrelationMatrix();
     92     }
     93 
     94     /**
     95      * Returns a {@link PearsonsCorrelation} instance constructed from the
     96      * ranked input data. That is,
     97      * <code>new SpearmansCorrelation(matrix).getRankCorrelation()</code>
     98      * is equivalent to
     99      * <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 }
    173