/// <summary> /// Performs a Spearman rank-order test of association between the two variables. /// </summary> /// <returns>The result of the test.</returns> /// <remarks> /// <para>The Spearman rank-order test of association is a non-parametric test for association between /// two variables. The test statistic rho is the correlation coefficient of the <em>rank</em> of /// each entry in the sample. It is thus invariant over monotonic reparameterizations of the data, /// and will, for example, detect a quadratic or exponential association just as well as a linear /// association.</para> /// <para>The Spearman rank-order test requires O(N log N) operations.</para> /// </remarks> /// <exception cref="InsufficientDataException">There are fewer than three data points.</exception> /// <seealso cref="PearsonRTest"/> /// <seealso cref="KendallTauTest"/> /// <seealso href="http://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient"/> public TestResult SpearmanRhoTest() { if (Count < 3) { throw new InsufficientDataException(); } // analytic expressions for the mean and variance of ranks double M = (Count - 1) / 2.0; double V = (Count + 1) * (Count - 1) / 12.0; // compute the covariance of ranks int[] rx = xData.GetRanks(); int[] ry = yData.GetRanks(); double C = 0.0; for (int i = 0; i < Count; i++) { C += (rx[i] - M) * (ry[i] - M); } C = C / Count; // compute rho double rho = C / V; // for small enough sample, use the exact distribution Distribution rhoDistribution; if (Count <= 10) { // for small enough sample, use the exact distribution // it would be nice to do this for at least slightly higher n, but computation time grows dramatically // would like to ensure return in less than 100ms; current timings n=10 35ms, n=11 72ms, n=12 190ms rhoDistribution = new DiscreteAsContinuousDistribution(new SpearmanExactDistribution(Count), Interval.FromEndpoints(-1.0, 1.0)); } else { // for larger samples, use the normal approximation // would like to fit support and C_4 too; look into logit-normal // i was not happy with Edgeworth expansion, which can fit C_4 but screws up tails badly, even giving negative probabilities rhoDistribution = new NormalDistribution(0.0, 1.0 / Math.Sqrt(Count - 1)); } return(new TestResult(rho, rhoDistribution)); }