/// <summary> /// Checks that (x-y) > threshold /// </summary> /// <remarks>Should be consistent with t.test(x, y, mu=threshold, alternative="greater") from R</remarks> public WelchResult IsGreater(Statistics x, Statistics y, Threshold threshold = null) { int n1 = x.N, n2 = y.N; if (x.N < 2) { throw new ArgumentException("x should contains at least 2 elements", nameof(x)); } if (y.N < 2) { throw new ArgumentException("y should contains at least 2 elements", nameof(y)); } double v1 = x.Variance, v2 = y.Variance, m1 = x.Mean, m2 = y.Mean; threshold = threshold ?? RelativeThreshold.Default; double thresholdValue = threshold.GetValue(x); double se = Math.Sqrt(v1 / n1 + v2 / n2); double t = ((m1 - m2) - thresholdValue) / se; double df = (v1 / n1 + v2 / n2).Sqr() / ((v1 / n1).Sqr() / (n1 - 1) + (v2 / n2).Sqr() / (n2 - 1)); double pValue = 1 - MathHelper.StudentOneTail(t, df); return(new WelchResult(t, df, pValue, threshold)); }
/// <summary> /// Checks that (x-y) > threshold /// </summary> /// <remarks>Should be consistent with wilcox.test(x, y, mu=threshold, alternative="greater") from R</remarks> public MannWhitneyResult IsGreater(double[] x, double[] y, Threshold threshold = null) { threshold = threshold ?? RelativeThreshold.Default; double thresholdValue = threshold.GetValue(new Statistics(x)); int n = x.Length, m = y.Length; if (Math.Min(n, m) < 3 || Math.Max(n, m) < 5) { return(null); // Test can't be applied } var xy = new double[n + m]; for (int i = 0; i < n; i++) { xy[i] = x[i]; } for (int i = 0; i < m; i++) { xy[n + i] = y[i] + thresholdValue; } var index = new int[n + m]; for (int i = 0; i < n + m; i++) { index[i] = i; } Array.Sort(index, (i, j) => xy[i].CompareTo(xy[j])); var ranks = new double[n + m]; for (int i = 0; i < n + m;) { int j = i; while (j + 1 < n + m && Math.Abs(xy[index[j + 1]] - xy[index[i]]) < 1e-9) { j++; } double rank = (i + j + 2) / 2.0; for (int k = i; k <= j; k++) { ranks[k] = rank; } i = j + 1; } double ux = 0; for (int i = 0; i < n + m; i++) { if (index[i] < n) { ux += ranks[i]; } } ux -= n * (n + 1) / 2.0; double uy = n * m - ux; if (n <= SmallN && m <= SmallN) { double pValue = 1 - PValueForSmallN(n, m, ux - 1); return(new MannWhitneyResult(ux, uy, pValue, threshold)); } else { double mu = n * m / 2.0; double su = Math.Sqrt(n * m * (n + m + 1) / 12.0); double z = (ux - mu) / su; double pValue = 1 - MathHelper.Gauss(z); return(new MannWhitneyResult(ux, uy, pValue, threshold)); } }