SpearmansCorrelation.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This is not the original file distributed by the Apache Software Foundation
* It has been modified by the Hipparchus project
*/
package org.hipparchus.stat.correlation;
import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.exception.MathIllegalArgumentException;
import org.hipparchus.linear.BlockRealMatrix;
import org.hipparchus.linear.RealMatrix;
import org.hipparchus.stat.LocalizedStatFormats;
import org.hipparchus.stat.ranking.NaNStrategy;
import org.hipparchus.stat.ranking.NaturalRanking;
import org.hipparchus.stat.ranking.RankingAlgorithm;
import org.hipparchus.util.MathArrays;
/**
* Spearman's rank correlation. This implementation performs a rank
* transformation on the input data and then computes {@link PearsonsCorrelation}
* on the ranked data.
* <p>
* By default, ranks are computed using {@link NaturalRanking} with default
* strategies for handling NaNs and ties in the data (NaNs maximal, ties averaged).
* The ranking algorithm can be set using a constructor argument.
*/
public class SpearmansCorrelation {
/** Input data */
private final RealMatrix data;
/** Ranking algorithm */
private final RankingAlgorithm rankingAlgorithm;
/** Rank correlation */
private final PearsonsCorrelation rankCorrelation;
/**
* Create a SpearmansCorrelation without data.
*/
public SpearmansCorrelation() {
this(new NaturalRanking());
}
/**
* Create a SpearmansCorrelation with the given ranking algorithm.
*
* @param rankingAlgorithm ranking algorithm
* @throws MathIllegalArgumentException if the provided {@link RankingAlgorithm} is of
* type {@link NaturalRanking} and uses a {@link NaNStrategy#REMOVED} strategy
*/
public SpearmansCorrelation(final RankingAlgorithm rankingAlgorithm)
throws MathIllegalArgumentException {
if (rankingAlgorithm instanceof NaturalRanking &&
NaNStrategy.REMOVED == ((NaturalRanking) rankingAlgorithm).getNanStrategy()) {
throw new MathIllegalArgumentException(LocalizedStatFormats.NOT_SUPPORTED_NAN_STRATEGY,
NaNStrategy.REMOVED);
}
data = null;
this.rankingAlgorithm = rankingAlgorithm;
rankCorrelation = null;
}
/**
* Create a SpearmansCorrelation from the given data matrix.
*
* @param dataMatrix matrix of data with columns representing
* variables to correlate
*/
public SpearmansCorrelation(final RealMatrix dataMatrix) {
this(dataMatrix, new NaturalRanking());
}
/**
* Create a SpearmansCorrelation with the given input data matrix
* and ranking algorithm.
*
* @param dataMatrix matrix of data with columns representing
* variables to correlate
* @param rankingAlgorithm ranking algorithm
* @throws MathIllegalArgumentException if the provided {@link RankingAlgorithm} is of
* type {@link NaturalRanking} and uses a {@link NaNStrategy#REMOVED} strategy
*/
public SpearmansCorrelation(final RealMatrix dataMatrix, final RankingAlgorithm rankingAlgorithm)
throws MathIllegalArgumentException {
if (rankingAlgorithm instanceof NaturalRanking &&
NaNStrategy.REMOVED == ((NaturalRanking) rankingAlgorithm).getNanStrategy()) {
throw new MathIllegalArgumentException(LocalizedStatFormats.NOT_SUPPORTED_NAN_STRATEGY,
NaNStrategy.REMOVED);
}
this.rankingAlgorithm = rankingAlgorithm;
this.data = rankTransform(dataMatrix);
rankCorrelation = new PearsonsCorrelation(data);
}
/**
* Calculate the Spearman Rank Correlation Matrix.
*
* @return Spearman Rank Correlation Matrix
* @throws NullPointerException if this instance was created with no data
*/
public RealMatrix getCorrelationMatrix() {
return rankCorrelation.getCorrelationMatrix();
}
/**
* Returns a {@link PearsonsCorrelation} instance constructed from the
* ranked input data. That is,
* <code>new SpearmansCorrelation(matrix).getRankCorrelation()</code>
* is equivalent to
* <code>new PearsonsCorrelation(rankTransform(matrix))</code> where
* <code>rankTransform(matrix)</code> is the result of applying the
* configured <code>RankingAlgorithm</code> to each of the columns of
* <code>matrix.</code>
*
* <p>Returns null if this instance was created with no data.</p>
*
* @return PearsonsCorrelation among ranked column data
*/
public PearsonsCorrelation getRankCorrelation() {
return rankCorrelation;
}
/**
* Computes the Spearman's rank correlation matrix for the columns of the
* input matrix.
*
* @param matrix matrix with columns representing variables to correlate
* @return correlation matrix
*/
public RealMatrix computeCorrelationMatrix(final RealMatrix matrix) {
final RealMatrix matrixCopy = rankTransform(matrix);
return new PearsonsCorrelation().computeCorrelationMatrix(matrixCopy);
}
/**
* Computes the Spearman's rank correlation matrix for the columns of the
* input rectangular array. The columns of the array represent values
* of variables to be correlated.
*
* @param matrix matrix with columns representing variables to correlate
* @return correlation matrix
*/
public RealMatrix computeCorrelationMatrix(final double[][] matrix) {
return computeCorrelationMatrix(new BlockRealMatrix(matrix));
}
/**
* Computes the Spearman's rank correlation coefficient between the two arrays.
*
* @param xArray first data array
* @param yArray second data array
* @return Returns Spearman's rank correlation coefficient for the two arrays
* @throws MathIllegalArgumentException if the arrays lengths do not match
* @throws MathIllegalArgumentException if the array length is less than 2
*/
public double correlation(final double[] xArray, final double[] yArray) {
MathArrays.checkEqualLength(xArray, yArray);
if (xArray.length < 2) {
throw new MathIllegalArgumentException(LocalizedCoreFormats.INSUFFICIENT_DIMENSION,
xArray.length, 2);
}
return new PearsonsCorrelation().correlation(rankingAlgorithm.rank(xArray),
rankingAlgorithm.rank(yArray));
}
/**
* Applies rank transform to each of the columns of <code>matrix</code>
* using the current <code>rankingAlgorithm</code>.
*
* @param matrix matrix to transform
* @return a rank-transformed matrix
*/
private RealMatrix rankTransform(final RealMatrix matrix) {
RealMatrix transformed = matrix.copy();
for (int i = 0; i < transformed.getColumnDimension(); i++) {
transformed.setColumn(i, rankingAlgorithm.rank(transformed.getColumn(i)));
}
return transformed;
}
}