Initial data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 72d218235f
commit f23f22d71c
199087 changed files with 3378941 additions and 0 deletions

View file

@ -0,0 +1,3 @@
---
from: http://rosettacode.org/wiki/P-value_correction
note: Probability and statistics

View file

@ -0,0 +1,33 @@
Given a list of [[wp:p-value|p-values]], adjust the p-values for multiple comparisons. This is done in order to control the false positive, or Type 1 error rate.
This is also known as the "[[wp:False discovery rate|false discovery rate]]" (FDR). After adjustment, the p-values will be higher but still inside [0,1].
The adjusted p-values are sometimes called "q-values".
;Task:
Given one list of [[Welch's_t-test|p-values]], return the p-values correcting for multiple comparisons
p = {4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03}
There are several methods to do this, see:
* Yoav Benjamini, Yosef Hochberg "[http://www.math.tau.ac.il/~ybenja/MyPapers/benjamini_hochberg1995.pdf Controlling the False Discovery Rate: A Practical and Powerful Approach to Multiple Testing]", ''Journal of the Royal Statistical Society. Series B'', Vol. 57, No. 1 (1995), pp. 289-300, JSTOR:[http://www.jstor.org/stable/2346101 2346101]
* Yoav Benjamini, Daniel Yekutieli, "[http://www.math.tau.ac.il/~ybenja/MyPapers/benjamini_yekutieli_ANNSTAT2001.pdf The control of the false discovery rate in multiple testing under dependency]", ''Ann. Statist.'', Vol. 29, No. 4 (2001), pp. 1165-1188, DOI:[https://doi.org/10.1214/aos/1013699998 10.1214/aos/1013699998] JSTOR:[http://www.jstor.org/stable/2674075 2674075]
* Sture Holm, "A Simple Sequentially Rejective Multiple Test Procedure", ''Scandinavian Journal of Statistics'', Vol. 6, No. 2 (1979), pp. 65-70, JSTOR:[https://www.jstor.org/stable/4615733 4615733]
* Yosef Hochberg, "A sharper Bonferroni procedure for multiple tests of significance", ''Biometrika'', Vol. 75, No. 4 (1988), pp 800802, DOI:[https://doi.org/10.1093/biomet/75.4.800 10.1093/biomet/75.4.800] JSTOR:[https://www.jstor.org/stable/2336325 2336325]
* Gerhard Hommel, "A stagewise rejective multiple test procedure based on a modified Bonferroni test", ''Biometrika'', Vol. 75, No. 2 (1988), pp 383386, DOI:[https://doi.org/10.1093/biomet/75.2.383 10.1093/biomet/75.2.383] JSTOR:[https://www.jstor.org/stable/2336190 2336190]
Each method has its own advantages and disadvantages.
<br><br>

View file

@ -0,0 +1,322 @@
#include <algorithm>
#include <functional>
#include <iostream>
#include <numeric>
#include <vector>
std::vector<int> seqLen(int start, int end) {
std::vector<int> result;
if (start == end) {
result.resize(end + 1);
std::iota(result.begin(), result.end(), 1);
} else if (start < end) {
result.resize(end - start + 1);
std::iota(result.begin(), result.end(), start);
} else {
result.resize(start - end + 1);
std::iota(result.rbegin(), result.rend(), end);
}
return result;
}
std::vector<int> order(const std::vector<double>& arr, bool decreasing) {
std::vector<int> idx(arr.size());
std::iota(idx.begin(), idx.end(), 0);
std::function<bool(int, int)> cmp;
if (decreasing) {
cmp = [&arr](int a, int b) { return arr[b] < arr[a]; };
} else {
cmp = [&arr](int a, int b) { return arr[a] < arr[b]; };
}
std::sort(idx.begin(), idx.end(), cmp);
return idx;
}
std::vector<double> cummin(const std::vector<double>& arr) {
if (arr.empty()) throw std::runtime_error("cummin requries at least one element");
std::vector<double> output(arr.size());
double cumulativeMin = arr[0];
std::transform(arr.cbegin(), arr.cend(), output.begin(), [&cumulativeMin](double a) {
if (a < cumulativeMin) cumulativeMin = a;
return cumulativeMin;
});
return output;
}
std::vector<double> cummax(const std::vector<double>& arr) {
if (arr.empty()) throw std::runtime_error("cummax requries at least one element");
std::vector<double> output(arr.size());
double cumulativeMax = arr[0];
std::transform(arr.cbegin(), arr.cend(), output.begin(), [&cumulativeMax](double a) {
if (cumulativeMax < a) cumulativeMax = a;
return cumulativeMax;
});
return output;
}
std::vector<double> pminx(const std::vector<double>& arr, double x) {
if (arr.empty()) throw std::runtime_error("pmin requries at least one element");
std::vector<double> result(arr.size());
std::transform(arr.cbegin(), arr.cend(), result.begin(), [&x](double a) {
if (a < x) return a;
return x;
});
return result;
}
void doubleSay(const std::vector<double>& arr) {
printf("[ 1] %.10f", arr[0]);
for (size_t i = 1; i < arr.size(); ++i) {
printf(" %.10f", arr[i]);
if ((i + 1) % 5 == 0) printf("\n[%2d]", i + 1);
}
}
std::vector<double> pAdjust(const std::vector<double>& pvalues, const std::string& str) {
if (pvalues.empty()) throw std::runtime_error("pAdjust requires at least one element");
size_t size = pvalues.size();
int type;
if ("bh" == str || "fdr" == str) {
type = 0;
} else if ("by" == str) {
type = 1;
} else if ("bonferroni" == str) {
type = 2;
} else if ("hochberg" == str) {
type = 3;
} else if ("holm" == str) {
type = 4;
} else if ("hommel" == str) {
type = 5;
} else {
throw std::runtime_error(str + " doesn't match any accepted FDR types");
}
// Bonferroni method
if (2 == type) {
std::vector<double> result(size);
for (size_t i = 0; i < size; ++i) {
double b = pvalues[i] * size;
if (b >= 1) {
result[i] = 1;
} else if (0 <= b && b < 1) {
result[i] = b;
} else {
throw std::runtime_error("a value is outside [0, 1)");
}
}
return result;
}
// Holm method
else if (4 == type) {
auto o = order(pvalues, false);
std::vector<double> o2Double(o.begin(), o.end());
std::vector<double> cummaxInput(size);
for (size_t i = 0; i < size; ++i) {
cummaxInput[i] = (size - i) * pvalues[o[i]];
}
auto ro = order(o2Double, false);
auto cummaxOutput = cummax(cummaxInput);
auto pmin = pminx(cummaxOutput, 1.0);
std::vector<double> result(size);
std::transform(ro.cbegin(), ro.cend(), result.begin(), [&pmin](int a) { return pmin[a]; });
return result;
}
// Hommel
else if (5 == type) {
auto indices = seqLen(size, size);
auto o = order(pvalues, false);
std::vector<double> p(size);
std::transform(o.cbegin(), o.cend(), p.begin(), [&pvalues](int a) { return pvalues[a]; });
std::vector<double> o2Double(o.begin(), o.end());
auto ro = order(o2Double, false);
std::vector<double> q(size);
std::vector<double> pa(size);
std::vector<double> npi(size);
for (size_t i = 0; i < size; ++i) {
npi[i] = p[i] * size / indices[i];
}
double min = *std::min_element(npi.begin(), npi.end());
std::fill(q.begin(), q.end(), min);
std::fill(pa.begin(), pa.end(), min);
for (int j = size; j >= 2; --j) {
auto ij = seqLen(1, size - j + 1);
std::transform(ij.cbegin(), ij.cend(), ij.begin(), [](int a) { return a - 1; });
int i2Length = j - 1;
std::vector<int> i2(i2Length);
for (int i = 0; i < i2Length; ++i) {
i2[i] = size - j + 2 + i - 1;
}
double q1 = j * p[i2[0]] / 2.0;
for (int i = 1; i < i2Length; ++i) {
double temp_q1 = p[i2[i]] * j / (2.0 + i);
if (temp_q1 < q1) q1 = temp_q1;
}
for (size_t i = 0; i < size - j + 1; ++i) {
q[ij[i]] = std::min(p[ij[i]] * j, q1);
}
for (int i = 0; i < i2Length; ++i) {
q[i2[i]] = q[size - j];
}
for (size_t i = 0; i < size; ++i) {
if (pa[i] < q[i]) {
pa[i] = q[i];
}
}
}
std::transform(ro.cbegin(), ro.cend(), q.begin(), [&pa](int a) { return pa[a]; });
return q;
}
std::vector<double> ni(size);
std::vector<int> o = order(pvalues, true);
std::vector<double> od(o.begin(), o.end());
for (size_t i = 0; i < size; ++i) {
if (pvalues[i] < 0 || pvalues[i]>1) {
throw std::runtime_error("a value is outside [0, 1]");
}
ni[i] = (double)size / (size - i);
}
auto ro = order(od, false);
std::vector<double> cumminInput(size);
if (0 == type) { // BH method
for (size_t i = 0; i < size; ++i) {
cumminInput[i] = ni[i] * pvalues[o[i]];
}
} else if (1 == type) { // BY method
double q = 0;
for (size_t i = 1; i < size + 1; ++i) {
q += 1.0 / i;
}
for (size_t i = 0; i < size; ++i) {
cumminInput[i] = q * ni[i] * pvalues[o[i]];
}
} else if (3 == type) { // Hochberg method
for (size_t i = 0; i < size; ++i) {
cumminInput[i] = (i + 1) * pvalues[o[i]];
}
}
auto cumminArray = cummin(cumminInput);
auto pmin = pminx(cumminArray, 1.0);
std::vector<double> result(size);
for (size_t i = 0; i < size; ++i) {
result[i] = pmin[ro[i]];
}
return result;
}
int main() {
using namespace std;
vector<double> pvalues{
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
};
vector<vector<double>> correctAnswers{
// Benjamini-Hochberg
{
6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02
},
// Benjamini & Yekutieli
{
1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02
},
// Bonferroni
{
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01
},
// Hochberg
{
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
},
// Holm
{
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
},
// Hommel
{
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01
}
};
vector<string> types{ "bh", "by", "bonferroni", "hochberg", "holm", "hommel" };
for (size_t type = 0; type < types.size(); ++type) {
auto q = pAdjust(pvalues, types[type]);
double error = 0.0;
for (size_t i = 0; i < pvalues.size(); ++i) {
error += abs(q[i] - correctAnswers[type][i]);
}
doubleSay(q);
printf("\ntype = %d = '%s' has a cumulative error of %g\n\n\n", type, types[type].c_str(), error);
}
return 0;
}

View file

@ -0,0 +1,332 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace PValueCorrection {
class Program {
static List<int> SeqLen(int start, int end) {
var result = new List<int>();
if (start == end) {
for (int i = 0; i < end + 1; ++i) {
result.Add(i + 1);
}
} else if (start < end) {
for (int i = 0; i < end - start + 1; ++i) {
result.Add(start + i);
}
} else {
for (int i = 0; i < start - end + 1; ++i) {
result.Add(start - i);
}
}
return result;
}
static List<int> Order(List<double> array, bool decreasing) {
List<int> idx = new List<int>();
for (int i = 0; i < array.Count; ++i) {
idx.Add(i);
}
IComparer<int> cmp;
if (decreasing) {
cmp = Comparer<int>.Create((a, b) => array[a] < array[b] ? 1 : array[b] < array[a] ? -1 : 0);
} else {
cmp = Comparer<int>.Create((a, b) => array[b] < array[a] ? 1 : array[a] < array[b] ? -1 : 0);
}
idx.Sort(cmp);
return idx;
}
static List<double> Cummin(List<double> array) {
if (array.Count < 1) throw new ArgumentOutOfRangeException("cummin requires at least one element");
var output = new List<double>();
double cumulativeMin = array[0];
for (int i = 0; i < array.Count; ++i) {
if (array[i] < cumulativeMin) cumulativeMin = array[i];
output.Add(cumulativeMin);
}
return output;
}
static List<double> Cummax(List<double> array) {
if (array.Count < 1) throw new ArgumentOutOfRangeException("cummax requires at least one element");
var output = new List<double>();
double cumulativeMax = array[0];
for (int i = 0; i < array.Count; ++i) {
if (array[i] > cumulativeMax) cumulativeMax = array[i];
output.Add(cumulativeMax);
}
return output;
}
static List<double> Pminx(List<double> array, double x) {
if (array.Count < 1) throw new ArgumentOutOfRangeException("pmin requires at least one element");
var result = new List<double>();
for (int i = 0; i < array.Count; ++i) {
if (array[i] < x) {
result.Add(array[i]);
} else {
result.Add(x);
}
}
return result;
}
static void Say(List<double> array) {
Console.Write("[ 1] {0:E}", array[0]);
for (int i = 1; i < array.Count; ++i) {
Console.Write(" {0:E}", array[i]);
if ((i + 1) % 5 == 0) Console.Write("\n[{0,2}]", i + 1);
}
Console.WriteLine();
}
static List<double> PAdjust(List<double> pvalues, string str) {
var size = pvalues.Count;
if (size < 1) throw new ArgumentOutOfRangeException("pAdjust requires at least one element");
int type;
switch (str.ToLower()) {
case "bh":
case "fdr":
type = 0;
break;
case "by":
type = 1;
break;
case "bonferroni":
type = 2;
break;
case "hochberg":
type = 3;
break;
case "holm":
type = 4;
break;
case "hommel":
type = 5;
break;
default:
throw new ArgumentException(str + " doesn't match any accepted FDR types");
}
if (2 == type) { // Bonferroni method
var result2 = new List<double>();
for (int i = 0; i < size; ++i) {
double b = pvalues[i] * size;
if (b >= 1) {
result2.Add(1);
} else if (0 <= b && b < 1) {
result2.Add(b);
} else {
throw new Exception(b + " is outside [0, 1)");
}
}
return result2;
} else if (4 == type) { // Holm method
var o4 = Order(pvalues, false);
var o4d = o4.ConvertAll(x => (double)x);
var cummaxInput = new List<double>();
for (int i = 0; i < size; ++i) {
cummaxInput.Add((size - i) * pvalues[o4[i]]);
}
var ro4 = Order(o4d, false);
var cummaxOutput = Cummax(cummaxInput);
var pmin4 = Pminx(cummaxOutput, 1.0);
var hr = new List<double>();
for (int i = 0; i < size; ++i) {
hr.Add(pmin4[ro4[i]]);
}
return hr;
} else if (5 == type) { // Hommel method
var indices = SeqLen(size, size);
var o5 = Order(pvalues, false);
var p = new List<double>();
for (int i = 0; i < size; ++i) {
p.Add(pvalues[o5[i]]);
}
var o5d = o5.ConvertAll(x => (double)x);
var ro5 = Order(o5d, false);
var q = new List<double>();
var pa = new List<double>();
var npi = new List<double>();
for (int i = 0; i < size; ++i) {
npi.Add(p[i] * size / indices[i]);
}
double min = npi.Min();
q.AddRange(Enumerable.Repeat(min, size));
pa.AddRange(Enumerable.Repeat(min, size));
for (int j = size; j >= 2; --j) {
var ij = SeqLen(1, size - j + 1);
for (int i = 0; i < size - j + 1; ++i) {
ij[i]--;
}
int i2Length = j - 1;
var i2 = new List<int>();
for (int i = 0; i < i2Length; ++i) {
i2.Add(size - j + 2 + i - 1);
}
double q1 = j * p[i2[0]] / 2.0;
for (int i = 1; i < i2Length; ++i) {
double temp_q1 = p[i2[i]] * j / (2.0 + i);
if (temp_q1 < q1) q1 = temp_q1;
}
for (int i = 0; i < size - j + 1; ++i) {
q[ij[i]] = Math.Min(p[ij[i]] * j, q1);
}
for (int i = 0; i < i2Length; ++i) {
q[i2[i]] = q[size - j];
}
for (int i = 0; i < size; ++i) {
if (pa[i] < q[i]) {
pa[i] = q[i];
}
}
}
for (int i = 0; i < size; ++i) {
q[i] = pa[ro5[i]];
}
return q;
}
var ni = new List<double>();
var o = Order(pvalues, true);
var od = o.ConvertAll(x => (double)x);
for (int i = 0; i < size; ++i) {
if (pvalues[i] < 0 || pvalues[i] > 1) {
throw new Exception("array[" + i + "] = " + pvalues[i] + " is outside [0, 1]");
}
ni.Add((double)size / (size - i));
}
var ro = Order(od, false);
var cumminInput = new List<double>();
if (0 == type) { // BH method
for (int i = 0; i < size; ++i) {
cumminInput.Add(ni[i] * pvalues[o[i]]);
}
} else if (1 == type) { // BY method
double q = 0;
for (int i = 1; i < size + 1; ++i) {
q += 1.0 / i;
}
for (int i = 0; i < size; ++i) {
cumminInput.Add(q * ni[i] * pvalues[o[i]]);
}
} else if (3 == type) { // Hochberg method
for (int i = 0; i < size; ++i) {
cumminInput.Add((i + 1) * pvalues[o[i]]);
}
}
var cumminArray = Cummin(cumminInput);
var pmin = Pminx(cumminArray, 1.0);
var result = new List<double>();
for (int i = 0; i < size; ++i) {
result.Add(pmin[ro[i]]);
}
return result;
}
static void Main(string[] args) {
var pvalues = new List<double> {
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
};
var correctAnswers = new List<List<double>> {
new List<double> { // Benjamini-Hochberg
6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02
},
new List<double> { // Benjamini & Yekutieli
1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02
},
new List<double> { // Bonferroni
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01
},
new List<double> { // Hochberg
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
},
new List<double> { // Holm
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
},
new List<double> { // Hommel
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01
}
};
string[] types = { "bh", "by", "bonferroni", "hochberg", "holm", "hommel" };
for (int type = 0; type < types.Length; ++type) {
var q = PAdjust(pvalues, types[type]);
double error = 0.0;
for (int i = 0; i < pvalues.Count; ++i) {
error += Math.Abs(q[i] - correctAnswers[type][i]);
}
Say(q);
Console.WriteLine("type {0} = '{1}' has a cumulative error of {2:E}", type, types[type], error);
Console.WriteLine();
}
}
}
}

View file

@ -0,0 +1,548 @@
#include <stdio.h>//printf
#include <stdlib.h>//qsort
#include <math.h>//fabs
#include <stdbool.h>//bool data type
#include <strings.h>//strcasecmp
#include <assert.h>//assert, necessary for random integer selection
unsigned int * seq_len(const unsigned int START, const unsigned int END) {
//named after R function of same name, but simpler function
unsigned start = (unsigned)START;
unsigned end = (unsigned)END;
if (START == END) {
unsigned int *restrict sequence = malloc( (end+1) * sizeof(unsigned int));
if (sequence == NULL) {
printf("malloc failed at %s line %u\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
for (unsigned i = 0; i < end; i++) {
sequence[i] = i+1;
}
return sequence;
}
if (START > END) {
end = (unsigned)START;
start = (unsigned)END;
}
const unsigned LENGTH = end - start ;
unsigned int *restrict sequence = malloc( (1+LENGTH) * sizeof(unsigned int));
if (sequence == NULL) {
printf("malloc failed at %s line %u\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
if (START < END) {
for (unsigned index = 0; index <= LENGTH; index++) {
sequence[index] = start + index;
}
} else {
for (unsigned index = 0; index <= LENGTH; index++) {
sequence[index] = end - index;
}
}
return sequence;
}
//modified from https://phoxis.org/2012/07/12/get-sorted-index-orderting-of-an-array/
double *restrict base_arr = NULL;
static int compar_increase (const void *restrict a, const void *restrict b) {
int aa = *((int *restrict ) a), bb = *((int *restrict) b);
if (base_arr[aa] < base_arr[bb]) {
return 1;
} else if (base_arr[aa] == base_arr[bb]) {
return 0;
} else {
return -1;
}
}
static int compar_decrease (const void *restrict a, const void *restrict b) {
int aa = *((int *restrict ) a), bb = *((int *restrict) b);
if (base_arr[aa] < base_arr[bb]) {
return -1;
} else if (base_arr[aa] == base_arr[bb]) {
return 0;
} else {
return 1;
}
}
unsigned int * order (const double *restrict ARRAY, const unsigned int SIZE, const bool DECREASING) {
//this has the same name as the same R function
unsigned int *restrict idx = malloc(SIZE * sizeof(unsigned int));
if (idx == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
base_arr = malloc(sizeof(double) * SIZE);
if (base_arr == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
for (unsigned int i = 0; i < SIZE; i++) {
base_arr[i] = ARRAY[i];
idx[i] = i;
}
if (DECREASING == false) {
qsort(idx, SIZE, sizeof(unsigned int), compar_decrease);
} else if (DECREASING == true) {
qsort(idx, SIZE, sizeof(unsigned int), compar_increase);
}
free(base_arr); base_arr = NULL;
return idx;
}
double * cummin(const double *restrict ARRAY, const unsigned int NO_OF_ARRAY_ELEMENTS) {
//this takes the same name of the R function which it copies
//this requires a free() afterward where it is used
if (NO_OF_ARRAY_ELEMENTS < 1) {
puts("cummin function requires at least one element.\n");
printf("Failed at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
double *restrict output = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (output == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
double cumulative_min = ARRAY[0];
for (unsigned int i = 0; i < NO_OF_ARRAY_ELEMENTS; i++) {
if (ARRAY[i] < cumulative_min) {
cumulative_min = ARRAY[i];
}
output[i] = cumulative_min;
}
return output;
}
double * cummax(const double *restrict ARRAY, const unsigned int NO_OF_ARRAY_ELEMENTS) {
//this takes the same name of the R function which it copies
//this requires a free() afterward where it is used
if (NO_OF_ARRAY_ELEMENTS < 1) {
puts("function requires at least one element.\n");
printf("Failed at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
double *restrict output = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (output == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
double cumulative_max = ARRAY[0];
for (unsigned int i = 0; i < NO_OF_ARRAY_ELEMENTS; i++) {
if (ARRAY[i] > cumulative_max) {
cumulative_max = ARRAY[i];
}
output[i] = cumulative_max;
}
return output;
}
double * pminx(const double *restrict ARRAY, const unsigned int NO_OF_ARRAY_ELEMENTS, const double X) {
//named after the R function pmin
if (NO_OF_ARRAY_ELEMENTS < 1) {
puts("pmin requires at least one element.\n");
printf("Failed at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
double *restrict pmin_array = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (pmin_array == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
if (ARRAY[index] < X) {
pmin_array[index] = ARRAY[index];
} else {
pmin_array[index] = X;
}
}
return pmin_array;
}
void double_say (const double *restrict ARRAY, const size_t NO_OF_ARRAY_ELEMENTS) {
printf("[1] %e", ARRAY[0]);
for (unsigned int i = 1; i < NO_OF_ARRAY_ELEMENTS; i++) {
printf(" %.10f", ARRAY[i]);
if (((i+1) % 5) == 0) {
printf("\n[%u]", i+1);
}
}
puts("\n");
}
/*void uint_say (const unsigned int *restrict ARRAY, const size_t NO_OF_ARRAY_ELEMENTS) {
//for debugging
printf("%u", ARRAY[0]);
for (size_t i = 1; i < NO_OF_ARRAY_ELEMENTS; i++) {
printf(",%u", ARRAY[i]);
}
puts("\n");
}*/
double * uint2double (const unsigned int *restrict ARRAY, const unsigned int NO_OF_ARRAY_ELEMENTS) {
double *restrict doubleArray = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (doubleArray == NULL) {
printf("Failure to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
doubleArray[index] = (double)ARRAY[index];
}
return doubleArray;
}
double min2 (const double N1, const double N2) {
if (N1 < N2) {
return N1;
} else {
return N2;
}
}
double * p_adjust (const double *restrict PVALUES, const unsigned int NO_OF_ARRAY_ELEMENTS, const char *restrict STRING) {
//this function is a translation of R's p.adjust "BH" method
// i is always i[index] = NO_OF_ARRAY_ELEMENTS - index - 1
if (NO_OF_ARRAY_ELEMENTS < 1) {
puts("p_adjust requires at least one element.\n");
printf("Failed at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
short int TYPE = -1;
if (STRING == NULL) {
TYPE = 0;
} else if (strcasecmp(STRING, "BH") == 0) {
TYPE = 0;
} else if (strcasecmp(STRING, "fdr") == 0) {
TYPE = 0;
} else if (strcasecmp(STRING, "by") == 0) {
TYPE = 1;
} else if (strcasecmp(STRING, "Bonferroni") == 0) {
TYPE = 2;
} else if (strcasecmp(STRING, "hochberg") == 0) {
TYPE = 3;
} else if (strcasecmp(STRING, "holm") == 0) {
TYPE = 4;
} else if (strcasecmp(STRING, "hommel") == 0) {
TYPE = 5;
} else {
printf("%s doesn't match any accepted FDR methods.\n", STRING);
printf("Failed at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
if (TYPE == 2) {//Bonferroni method
double *restrict bonferroni = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (bonferroni == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
const double BONFERRONI = PVALUES[index] * NO_OF_ARRAY_ELEMENTS;
if (BONFERRONI >= 1.0) {
bonferroni[index] = 1.0;
} else if ((0.0 <= BONFERRONI) && (BONFERRONI < 1.0)) {
bonferroni[index] = BONFERRONI;
} else {
printf("%g is outside of the interval I planned.\n", BONFERRONI);
printf("Failure at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
}
return bonferroni;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
} else if (TYPE == 4) {//Holm method
/*these values are computed separately from BH, BY, and Hochberg because they are
computed differently*/
unsigned int *restrict o = order(PVALUES, NO_OF_ARRAY_ELEMENTS, false);
//sorted in reverse of methods 0-3
double *restrict o2double = uint2double(o, NO_OF_ARRAY_ELEMENTS);
double *restrict cummax_input = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
for (unsigned index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
cummax_input[index] = (NO_OF_ARRAY_ELEMENTS - index ) * (double)PVALUES[o[index]];
// printf("cummax_input[%zu] = %e\n", index, cummax_input[index]);
}
free(o); o = NULL;
unsigned int *restrict ro = order(o2double, NO_OF_ARRAY_ELEMENTS, false);
free(o2double); o2double = NULL;
double *restrict cummax_output = cummax(cummax_input, NO_OF_ARRAY_ELEMENTS);
free(cummax_input); cummax_input = NULL;
double *restrict pmin = pminx(cummax_output, NO_OF_ARRAY_ELEMENTS, 1);
free(cummax_output); cummax_output = NULL;
double *restrict qvalues = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
qvalues[index] = pmin[ro[index]];
}
free(pmin); pmin = NULL;
free(ro); ro = NULL;
return qvalues;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
} else if (TYPE == 5) {//Hommel method
//i <- seq_len(n)
//o <- order(p)
unsigned int *restrict o = order(PVALUES, NO_OF_ARRAY_ELEMENTS, false);//false is R's default
//p <- p[o]
double *restrict p = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (p == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
p[index] = PVALUES[o[index]];
}
//ro <- order(o)
double *restrict o2double = uint2double(o, NO_OF_ARRAY_ELEMENTS);
free(o); o = NULL;
unsigned int *restrict ro = order(o2double, NO_OF_ARRAY_ELEMENTS, false);
free(o2double); o2double = NULL;
// puts("ro");
//q <- pa <- rep.int(min(n * p/i), n)
double *restrict q = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (q == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
double *restrict pa = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (pa == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
double min = (double)NO_OF_ARRAY_ELEMENTS * p[0];
for (unsigned index = 1; index < NO_OF_ARRAY_ELEMENTS; index++) {
const double TEMP = (double)NO_OF_ARRAY_ELEMENTS * p[index] / (double)(1+index);
if (TEMP < min) {
min = TEMP;
}
}
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
pa[index] = min;
q[index] = min;
}
// puts("q & pa");
// double_say(q, NO_OF_ARRAY_ELEMENTS);
/*for (j in (n - 1):2) {
ij <- seq_len(n - j + 1)
i2 <- (n - j + 2):n
q1 <- min(j * p[i2]/(2:j))
q[ij] <- pmin(j * p[ij], q1)
q[i2] <- q[n - j + 1]
pa <- pmax(pa, q)
}
*/
for (unsigned j = (NO_OF_ARRAY_ELEMENTS-1); j >= 2; j--) {
// printf("j = %zu\n", j);
unsigned int *restrict ij = seq_len(0,NO_OF_ARRAY_ELEMENTS - j);
const size_t I2_LENGTH = j - 1;
unsigned int *restrict i2 = malloc(I2_LENGTH * sizeof(unsigned int));
for (unsigned i = 0; i < I2_LENGTH; i++) {
i2[i] = NO_OF_ARRAY_ELEMENTS-j+2+i-1;
//R's indices are 1-based, C's are 0-based, I added the -1
}
double q1 = (double)j * p[i2[0]] / 2.0;
for (unsigned int i = 1; i < I2_LENGTH; i++) {//loop through 2:j
const double TEMP_Q1 = (double)j * p[i2[i]] / (double)(2 + i);
if (TEMP_Q1 < q1) {
q1 = TEMP_Q1;
}
}
for (unsigned int i = 0; i < (NO_OF_ARRAY_ELEMENTS - j + 1); i++) {//q[ij] <- pmin(j * p[ij], q1)
q[ij[i]] = min2( (double)j*p[ij[i]], q1);
}
free(ij); ij = NULL;
for (unsigned int i = 0; i < I2_LENGTH; i++) {//q[i2] <- q[n - j + 1]
q[i2[i]] = q[NO_OF_ARRAY_ELEMENTS - j];//subtract 1 because of starting index difference
}
free(i2); i2 = NULL;
for (unsigned int i = 0; i < NO_OF_ARRAY_ELEMENTS; i++) {//pa <- pmax(pa, q)
if (pa[i] < q[i]) {
pa[i] = q[i];
}
}
// printf("j = %zu, pa = \n", j);
// double_say(pa, N);
}//end j loop
free(p); p = NULL;
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
q[index] = pa[ro[index]];//Hommel q-values
}
//now free memory
free(ro); ro = NULL;
free(pa); pa = NULL;
return q;
}
//The methods are similarly computed and thus can be combined for clarity
unsigned int *restrict o = order(PVALUES, NO_OF_ARRAY_ELEMENTS, true);
if (o == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
double *restrict o_double = uint2double(o, NO_OF_ARRAY_ELEMENTS);
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
if ((PVALUES[index] < 0) || (PVALUES[index] > 1)) {
printf("array[%u] = %lf, which is outside the interval [0,1]\n", index, PVALUES[index]);
printf("died at %s line %u\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
}
unsigned int *restrict ro = order(o_double, NO_OF_ARRAY_ELEMENTS, false);
if (ro == NULL) {
printf("failed to malloc at %s line %u.\n", __FILE__, __LINE__);
perror("");
exit(EXIT_FAILURE);
}
free(o_double); o_double = NULL;
double *restrict cummin_input = malloc(sizeof(double) * NO_OF_ARRAY_ELEMENTS);
if (TYPE == 0) {//BH method
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
const double NI = (double)NO_OF_ARRAY_ELEMENTS / (double)(NO_OF_ARRAY_ELEMENTS - index);// n/i simplified
cummin_input[index] = NI * PVALUES[o[index]];//PVALUES[o[index]] is p[o]
}
} else if (TYPE == 1) {//BY method
double q = 1.0;
for (unsigned int index = 2; index < (1+NO_OF_ARRAY_ELEMENTS); index++) {
q += 1.0/(double)index;
}
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
const double NI = (double)NO_OF_ARRAY_ELEMENTS / (double)(NO_OF_ARRAY_ELEMENTS - index);// n/i simplified
cummin_input[index] = q * NI * PVALUES[o[index]];//PVALUES[o[index]] is p[o]
}
} else if (TYPE == 3) {//Hochberg method
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
// pmin(1, cummin((n - i + 1L) * p[o]))[ro]
cummin_input[index] = (double)(index + 1) * PVALUES[o[index]];
}
}
free(o); o = NULL;
double *restrict cummin_array = NULL;
cummin_array = cummin(cummin_input, NO_OF_ARRAY_ELEMENTS);
free(cummin_input); cummin_input = NULL;//I don't need this anymore
double *restrict pmin = pminx(cummin_array, NO_OF_ARRAY_ELEMENTS, 1);
free(cummin_array); cummin_array = NULL;
double *restrict q_array = malloc(NO_OF_ARRAY_ELEMENTS*sizeof(double));
for (unsigned int index = 0; index < NO_OF_ARRAY_ELEMENTS; index++) {
q_array[index] = pmin[ro[index]];
}
free(ro); ro = NULL;
free(pmin); pmin = NULL;
return q_array;
}
int main(void) {
const double PVALUES[] = {4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03};//just the pvalues
const double CORRECT_ANSWERS[6][50] = {//each first index is type
{6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02},//Benjamini-Hochberg
{1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02},//Benjamini & Yekutieli
{1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01},//Bonferroni
{9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01},//Hochberg
{1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01},//Holm
{ 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01}//Hommel
};
//the following loop checks each type with R's answers
const char *restrict TYPES[] = {"bh", "by", "bonferroni", "hochberg", "holm", "hommel"};
for (unsigned short int type = 0; type <= 5; type++) {
double *restrict q = p_adjust(PVALUES, sizeof(PVALUES) / sizeof(*PVALUES), TYPES[type]);
double error = fabs(q[0] - CORRECT_ANSWERS[type][0]);
// printf("%e - %e = %g\n", q[0], CORRECT_ANSWERS[type][0], error);
// puts("p q");
// printf("%g\t%g\n", pvalues[0], q[0]);
for (unsigned int i = 1; i < sizeof(PVALUES) / sizeof(*PVALUES); i++) {
const double this_error = fabs(q[i] - CORRECT_ANSWERS[type][i]);
// printf("%e - %e = %g\n", q[i], CORRECT_ANSWERS[type][i], error);
error += this_error;
}
double_say(q, sizeof(PVALUES) / sizeof(*PVALUES));
free(q); q = NULL;
printf("\ntype %u = '%s' has cumulative error of %g\n", type, TYPES[type], error);
}
return 0;
}

View file

@ -0,0 +1,195 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SIZE 50
#define each_i(start, end) for (i = start; i < end; ++i)
typedef enum { UP, DOWN } direction;
typedef struct { int index; double value; } iv1;
typedef struct { int index; int value; } iv2;
/* test also for 'Unknown' correction type */
const char *types[8] = {
"Benjamini-Hochberg", "Benjamini-Yekutieli", "Bonferroni", "Hochberg",
"Holm", "Hommel", "Šidák", "Unknown"
};
int compare_iv1(const void *a, const void *b) {
double aa = ((iv1 *)a) -> value;
double bb = ((iv1 *)b) -> value;
if (aa > bb) return 1;
if (aa < bb) return -1;
return 0;
}
int compare_iv1_desc(const void *a, const void *b) {
return -compare_iv1(a, b);
}
int compare_iv2(const void *a, const void *b) {
return ((iv2 *)a) -> value - ((iv2 *)b) -> value;
}
void ratchet(double *pa, direction dir) {
int i;
double m = pa[0];
if (dir == UP) {
each_i(1, SIZE) {
if (pa[i] > m) pa[i] = m;
m = pa[i];
}
}
else {
each_i(1, SIZE) {
if (pa[i] < m) pa[i] = m;
m = pa[i];
}
}
each_i(0, SIZE) if (pa[i] > 1.0) pa[i] = 1.0;
}
void schwartzian(const double *p, double *pa, direction dir) {
int i;
int order[SIZE];
int order2[SIZE];
iv1 iv1s[SIZE];
iv2 iv2s[SIZE];
double pa2[SIZE];
each_i(0, SIZE) { iv1s[i].index = i; iv1s[i].value = p[i]; }
if (dir == UP)
qsort(iv1s, SIZE, sizeof(iv1s[0]), compare_iv1_desc);
else
qsort(iv1s, SIZE, sizeof(iv1s[0]), compare_iv1);
each_i(0, SIZE) order[i] = iv1s[i].index;
each_i(0, SIZE) pa[i] *= p[order[i]];
ratchet(pa, dir);
each_i(0, SIZE) { iv2s[i].index = i; iv2s[i].value = order[i]; }
qsort(iv2s, SIZE, sizeof(iv2s[0]), compare_iv2);
each_i(0, SIZE) order2[i] = iv2s[i].index;
each_i(0, SIZE) pa2[i] = pa[order2[i]];
each_i(0, SIZE) pa[i] = pa2[i];
}
void adjust(const double *p, double *pa, const char *type) {
int i;
if (!strcmp(type, "Benjamini-Hochberg")) {
each_i(0, SIZE) pa[i] = (double)SIZE / (SIZE - i);
schwartzian(p, pa, UP);
}
else if (!strcmp(type, "Benjamini-Yekutieli")) {
double q = 0.0;
each_i(1, SIZE + 1) q += 1.0 / i;
each_i(0, SIZE) pa[i] = q * SIZE / (SIZE - i);
schwartzian(p, pa, UP);
}
else if (!strcmp(type, "Bonferroni")) {
each_i(0, SIZE) pa[i] = (p[i] * SIZE > 1.0) ? 1.0 : p[i] * SIZE;
}
else if (!strcmp(type, "Hochberg")) {
each_i(0, SIZE) pa[i] = i + 1.0;
schwartzian(p, pa, UP);
}
else if (!strcmp(type, "Holm")) {
each_i(0, SIZE) pa[i] = SIZE - i;
schwartzian(p, pa, DOWN);
}
else if (!strcmp(type, "Hommel")) {
int i, j;
int order[SIZE];
int order2[SIZE];
iv1 iv1s[SIZE];
iv2 iv2s[SIZE];
double s[SIZE];
double q[SIZE];
double pa2[SIZE];
int indices[SIZE];
each_i(0, SIZE) { iv1s[i].index = i; iv1s[i].value = p[i]; }
qsort(iv1s, SIZE, sizeof(iv1s[0]), compare_iv1);
each_i(0, SIZE) order[i] = iv1s[i].index;
each_i(0, SIZE) s[i] = p[order[i]];
double min = s[0] * SIZE;
each_i(1, SIZE) {
double temp = s[i] / (i + 1.0);
if (temp < min) min = temp;
}
each_i(0, SIZE) q[i] = min;
each_i(0, SIZE) pa2[i] = min;
for (j = SIZE - 1; j >= 2; --j) {
each_i(0, SIZE) indices[i] = i;
int upper_start = SIZE - j + 1; /* upper indices start index */
int upper_size = j - 1; /* size of upper indices */
int lower_size = SIZE - upper_size; /* size of lower indices */
double qmin = j * s[indices[upper_start]] / 2.0;
each_i(1, upper_size) {
double temp = s[indices[upper_start + i]] * j / (2.0 + i);
if (temp < qmin) qmin = temp;
}
each_i(0, lower_size) {
double temp = s[indices[i]] * j;
q[indices[i]] = (temp < qmin) ? temp : qmin;
}
each_i(0, upper_size) q[indices[upper_start + i]] = q[SIZE - j];
each_i(0, SIZE) if (pa2[i] < q[i]) pa2[i] = q[i];
}
each_i(0, SIZE) { iv2s[i].index = i; iv2s[i].value = order[i]; }
qsort(iv2s, SIZE, sizeof(iv2s[0]), compare_iv2);
each_i(0, SIZE) order2[i] = iv2s[i].index;
each_i(0, SIZE) pa[i] = pa2[order2[i]];
}
else if (!strcmp(type, "Šidák")) {
each_i(0, SIZE) pa[i] = 1.0 - pow(1.0 - p[i], SIZE);
}
else {
printf("\nSorry, do not know how to do '%s' correction.\n", type);
printf("Perhaps you want one of these?:\n");
each_i(0, 7) printf(" %s\n", types[i]);
exit(1);
}
}
void adjusted(const double *p, const char *type) {
int i;
double pa[SIZE] = { 0.0 };
if (check(p)) {
adjust(p, pa, type);
printf("\n%s", type);
each_i(0, SIZE) {
if (!(i % 5)) printf("\n[%2d] ", i);
printf("%1.10f ", pa[i]);
}
printf("\n");
}
else {
printf("p-values must be in range 0.0 to 1.0\n");
exit(1);
}
}
int check(const double* p) {
int i;
each_i(0, SIZE) {
if (p[i] < 0.0 || p[i] > 1.0) return 0;
}
return 1;
}
int main() {
int i;
double p_values[SIZE] = {
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
};
each_i(0, 8) adjusted(p_values, types[i]);
return 0;
}

View file

@ -0,0 +1,340 @@
import std.algorithm;
import std.conv;
import std.math;
import std.stdio;
import std.string;
int[] seqLen(int start, int end) {
int[] result;
if (start == end) {
result.length = end+1;
for (int i; i<result.length; i++) {
result[i] = i+1;
}
} else if (start < end) {
result.length = end - start + 1;
for (int i; i<result.length; i++) {
result[i] = start+i;
}
} else {
result.length = start - end + 1;
for (int i; i<result.length; i++) {
result[i] = start-i;
}
}
return result;
}
int[] order(double[] array, bool decreasing) {
int size = array.length;
int[] idx;
idx.length = size;
double[] baseArr;
baseArr.length = size;
for (int i; i<size; i++) {
baseArr[i] = array[i];
idx[i] = i;
}
if (!decreasing) {
alias comp = (a,b) => baseArr[a] < baseArr[b];
idx.sort!comp;
} else {
alias comp = (a,b) => baseArr[b] < baseArr[a];
idx.sort!comp;
}
return idx;
}
double[] cummin(double[] array) {
int size = array.length;
if (size < 1) throw new Exception("cummin requires at least one element");
double[] output;
output.length = size;
auto cumulativeMin = array[0];
foreach (i; 0..size) {
if (array[i] < cumulativeMin) cumulativeMin = array[i];
output[i] = cumulativeMin;
}
return output;
}
double[] cummax(double[] array) {
auto size = array.length;
if (size < 1) throw new Exception("cummax requires at least one element");
double[] output;
output.length = size;
auto cumulativeMax = array[0];
foreach (i; 0..size) {
if (array[i] > cumulativeMax) cumulativeMax = array[i];
output[i] = cumulativeMax;
}
return output;
}
double[] pminx(double[] array, double x) {
auto size = array.length;
if (size < 1) throw new Exception("pmin requires at least one element");
double[] result;
result.length = size;
foreach (i; 0..size) {
if (array[i] < x) {
result[i] = array[i];
} else {
result[i] = x;
}
}
return result;
}
void doubleSay(double[] array) {
writef("[ 1] %e", array[0]);
foreach (i; 1..array.length) {
writef(" %.10f", array[i]);
if ((i+1) % 5 == 0) writef("\n[%2d]", i+1);
}
writeln;
}
auto toArray(T,U)(U[] array) {
T[] result;
result.length = array.length;
foreach(i; 0..array.length) {
result[i] = to!T(array[i]);
}
return result;
}
double[] pAdjust(double[] pvalues, string str) {
auto size = pvalues.length;
if (size < 1) throw new Exception("pAdjust requires at least one element");
int type = str.toLower.predSwitch!"a==b"(
"bh", 0,
"fdr", 0,
"by", 1,
"bonferroni", 2,
"hochberg", 3,
"holm", 4,
"hommel", 5,
{ throw new Exception(text("'",str,"' doesn't match any accepted FDR types")); }()
);
if (type == 2) { // Bonferroni method
double[] result;
result.length = size;
foreach (i; 0..size) {
auto b = pvalues[i] * size;
if (b >= 1) {
result[i] = 1;
} else if (0 <= b && b < 1) {
result[i] = b;
} else {
throw new Exception(text(b," is outside [0, 1)"));
}
}
return result;
} else if (type == 4) { // Holm method
auto o = order(pvalues, false);
auto o2Double = toArray!(double,int)(o);
double[] cummaxInput;
cummaxInput.length = size;
foreach (i; 0..size) {
cummaxInput[i] = (size-i) * pvalues[o[i]];
}
auto ro = order(o2Double, false);
auto cummaxOutput = cummax(cummaxInput);
auto pmin = pminx(cummaxOutput, 1.0);
double[] result;
result.length = size;
foreach (i; 0..size) {
result[i] = pmin[ro[i]];
}
return result;
} else if (type == 5) {
auto indices = seqLen(size, size);
auto o = order(pvalues, false);
double[] p;
p.length = size;
foreach (i; 0..size) {
p[i] = pvalues[o[i]];
}
auto o2Double = toArray!double(o);
auto ro = order(o2Double, false);
double[] q;
q.length = size;
double[] pa;
pa.length = size;
double[] npi;
npi.length = size;
foreach (i; 0..size) {
npi[i] = p[i] * size / indices[i];
}
auto min_ = reduce!min(npi);
q[] = min_;
pa[] = min_;
foreach_reverse (j; 2..size) {
auto ij = seqLen(1, size - j + 1);
foreach (i; 0..size-j+1) {
ij[i]--;
}
auto i2Length = j-1;
int[] i2;
i2.length = i2Length;
foreach(i; 0..i2Length) {
i2[i] = size-j+2+i-1;
}
auto pi2Length = i2Length;
double q1 = j*p[i2[0]] / 2.0;
foreach (i; 1..pi2Length) {
auto temp_q1 = p[i2[i]] * j / (2.0 + i);
if (temp_q1 < q1) q1 = temp_q1;
}
foreach (i; 0..size-j+1) {
q[ij[i]] = min(p[ij[i]] * j, q1);
}
foreach(i; 0..i2Length) {
q[i2[i]] = q[size-j];
}
foreach(i; 0..size) if (pa[i] < q[i]) pa[i] = q[i];
}
foreach (index; 0..size) {
q[index] = pa[ro[index]];
}
return q;
}
double[] ni;
ni.length = size;
auto o = order(pvalues, true);
auto oDouble = toArray!double(o);
foreach (index; 0..size) {
if (pvalues[index] < 0 || pvalues[index] > 1) {
throw new Exception(text("array[", index, "] = ", pvalues[index], " is outside [0, 1]"));
}
ni[index] = cast(double) size / (size - index);
}
auto ro = order(oDouble, false);
double[] cumminInput;
cumminInput.length = size;
if (type == 0) { // BH method
foreach (index; 0..size) {
cumminInput[index] = ni[index] * pvalues[o[index]];
}
} else if (type == 1) { // BY method
double q = 0;
foreach (index; 1..size+1) q += 1.0 / index;
foreach (index; 0..size) {
cumminInput[index] = q * ni[index] * pvalues[o[index]];
}
} else if (type == 3) { // Hochberg method
foreach (index; 0..size) {
cumminInput[index] = (index + 1) * pvalues[o[index]];
}
}
auto cumminArray =cummin(cumminInput);
auto pmin = pminx(cumminArray, 1.0);
double[] result;
result.length = size;
foreach (i; 0..size) {
result[i] = pmin[ro[i]];
}
return result;
}
void main() {
double[] pvalues = [
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
];
double[][] correctAnswers = [
[ // Benjamini-Hochberg
6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02
],
[ // Benjamini & Yekutieli
1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02
],
[ // Bonferroni
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01
],
[ // Hochberg
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
],
[ // Holm
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
],
[ // Hommel
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01
]
];
auto types = ["bh", "by", "bonferroni", "hochberg", "holm", "hommel"];
foreach (type; 0..types.length) {
auto q = pAdjust(pvalues, types[type]);
double error = 0.0;
foreach (i; 0..pvalues.length) {
error += abs(q[i] - correctAnswers[type][i]);
}
doubleSay(q);
writefln("\ntype %d = '%s' has a cumulative error of %g", type, types[type], error);
}
}

View file

@ -0,0 +1,304 @@
package main
import (
"fmt"
"log"
"math"
"os"
"sort"
"strconv"
"strings"
)
type pvalues = []float64
type iv1 struct {
index int
value float64
}
type iv2 struct{ index, value int }
type direction int
const (
up direction = iota
down
)
// Test also for 'Unknown' correction type.
var ctypes = []string{
"Benjamini-Hochberg", "Benjamini-Yekutieli", "Bonferroni", "Hochberg",
"Holm", "Hommel", "Šidák", "Unknown",
}
func minimum(p pvalues) float64 {
m := p[0]
for i := 1; i < len(p); i++ {
if p[i] < m {
m = p[i]
}
}
return m
}
func maximum(p pvalues) float64 {
m := p[0]
for i := 1; i < len(p); i++ {
if p[i] > m {
m = p[i]
}
}
return m
}
func adjusted(p pvalues, ctype string) (string, error) {
err := check(p)
if err != nil {
return "", err
}
temp := pformat(adjust(p, ctype), 5)
return fmt.Sprintf("\n%s\n%s", ctype, temp), nil
}
func pformat(p pvalues, cols int) string {
var lines []string
for i := 0; i < len(p); i += cols {
fchunk := p[i : i+cols]
schunk := make([]string, cols)
for j := 0; j < cols; j++ {
schunk[j] = strconv.FormatFloat(fchunk[j], 'f', 10, 64)
}
lines = append(lines, fmt.Sprintf("[%2d] %s", i, strings.Join(schunk, " ")))
}
return strings.Join(lines, "\n")
}
func check(p []float64) error {
cond := len(p) > 0 && minimum(p) >= 0 && maximum(p) <= 1
if !cond {
return fmt.Errorf("p-values must be in range 0.0 to 1.0")
}
return nil
}
func ratchet(p pvalues, dir direction) {
size := len(p)
m := p[0]
if dir == up {
for i := 1; i < size; i++ {
if p[i] > m {
p[i] = m
}
m = p[i]
}
} else {
for i := 1; i < size; i++ {
if p[i] < m {
p[i] = m
}
m = p[i]
}
}
for i := 0; i < size; i++ {
if p[i] > 1.0 {
p[i] = 1.0
}
}
}
func schwartzian(p pvalues, mult pvalues, dir direction) pvalues {
size := len(p)
order := make([]int, size)
iv1s := make([]iv1, size)
for i := 0; i < size; i++ {
iv1s[i] = iv1{i, p[i]}
}
if dir == up {
sort.Slice(iv1s, func(i, j int) bool {
return iv1s[i].value > iv1s[j].value
})
} else {
sort.Slice(iv1s, func(i, j int) bool {
return iv1s[i].value < iv1s[j].value
})
}
for i := 0; i < size; i++ {
order[i] = iv1s[i].index
}
pa := make(pvalues, size)
for i := 0; i < size; i++ {
pa[i] = mult[i] * p[order[i]]
}
ratchet(pa, dir)
order2 := make([]int, size)
iv2s := make([]iv2, size)
for i := 0; i < size; i++ {
iv2s[i] = iv2{i, order[i]}
}
sort.Slice(iv2s, func(i, j int) bool {
return iv2s[i].value < iv2s[j].value
})
for i := 0; i < size; i++ {
order2[i] = iv2s[i].index
}
pa2 := make(pvalues, size)
for i := 0; i < size; i++ {
pa2[i] = pa[order2[i]]
}
return pa2
}
func adjust(p pvalues, ctype string) pvalues {
size := len(p)
if size == 0 {
return p
}
fsize := float64(size)
switch ctype {
case "Benjamini-Hochberg":
mult := make(pvalues, size)
for i := 0; i < size; i++ {
mult[i] = fsize / float64(size-i)
}
return schwartzian(p, mult, up)
case "Benjamini-Yekutieli":
q := 0.0
for i := 1; i <= size; i++ {
q += 1.0 / float64(i)
}
mult := make(pvalues, size)
for i := 0; i < size; i++ {
mult[i] = q * fsize / (fsize - float64(i))
}
return schwartzian(p, mult, up)
case "Bonferroni":
p2 := make(pvalues, size)
for i := 0; i < size; i++ {
p2[i] = math.Min(p[i]*fsize, 1.0)
}
return p2
case "Hochberg":
mult := make(pvalues, size)
for i := 0; i < size; i++ {
mult[i] = float64(i) + 1
}
return schwartzian(p, mult, up)
case "Holm":
mult := make(pvalues, size)
for i := 0; i < size; i++ {
mult[i] = fsize - float64(i)
}
return schwartzian(p, mult, down)
case "Hommel":
order := make([]int, size)
iv1s := make([]iv1, size)
for i := 0; i < size; i++ {
iv1s[i] = iv1{i, p[i]}
}
sort.Slice(iv1s, func(i, j int) bool {
return iv1s[i].value < iv1s[j].value
})
for i := 0; i < size; i++ {
order[i] = iv1s[i].index
}
s := make(pvalues, size)
for i := 0; i < size; i++ {
s[i] = p[order[i]]
}
m := make(pvalues, size)
for i := 0; i < size; i++ {
m[i] = s[i] * fsize / (float64(i) + 1)
}
min := minimum(m)
q := make(pvalues, size)
for i := 0; i < size; i++ {
q[i] = min
}
pa := make(pvalues, size)
for i := 0; i < size; i++ {
pa[i] = min
}
for j := size - 1; j >= 2; j-- {
lower := make([]int, size-j+1) // lower indices
for i := 0; i < len(lower); i++ {
lower[i] = i
}
upper := make([]int, j-1) // upper indices
for i := 0; i < len(upper); i++ {
upper[i] = size - j + 1 + i
}
qmin := float64(j) * s[upper[0]] / 2.0
for i := 1; i < len(upper); i++ {
temp := s[upper[i]] * float64(j) / (2.0 + float64(i))
if temp < qmin {
qmin = temp
}
}
for i := 0; i < len(lower); i++ {
q[lower[i]] = math.Min(s[lower[i]]*float64(j), qmin)
}
for i := 0; i < len(upper); i++ {
q[upper[i]] = q[size-j]
}
for i := 0; i < size; i++ {
if pa[i] < q[i] {
pa[i] = q[i]
}
}
}
order2 := make([]int, size)
iv2s := make([]iv2, size)
for i := 0; i < size; i++ {
iv2s[i] = iv2{i, order[i]}
}
sort.Slice(iv2s, func(i, j int) bool {
return iv2s[i].value < iv2s[j].value
})
for i := 0; i < size; i++ {
order2[i] = iv2s[i].index
}
pa2 := make(pvalues, size)
for i := 0; i < size; i++ {
pa2[i] = pa[order2[i]]
}
return pa2
case "Šidák":
p2 := make(pvalues, size)
for i := 0; i < size; i++ {
p2[i] = 1.0 - math.Pow(1.0-float64(p[i]), fsize)
}
return p2
default:
fmt.Printf("\nSorry, do not know how to do '%s' correction.\n", ctype)
fmt.Println("Perhaps you want one of these?:")
temp := make([]string, len(ctypes)-1)
for i := 0; i < len(temp); i++ {
temp[i] = fmt.Sprintf(" %s", ctypes[i])
}
fmt.Println(strings.Join(temp, "\n"))
os.Exit(1)
}
return p
}
func main() {
p := pvalues{
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03,
}
for _, ctype := range ctypes {
s, err := adjusted(p, ctype)
if err != nil {
log.Fatal(err)
}
fmt.Println(s)
}
}

View file

@ -0,0 +1,350 @@
import java.util.Arrays;
import java.util.Comparator;
public class PValueCorrection {
private static int[] seqLen(int start, int end) {
int[] result;
if (start == end) {
result = new int[end + 1];
for (int i = 0; i < result.length; ++i) {
result[i] = i + 1;
}
} else if (start < end) {
result = new int[end - start + 1];
for (int i = 0; i < result.length; ++i) {
result[i] = start + i;
}
} else {
result = new int[start - end + 1];
for (int i = 0; i < result.length; ++i) {
result[i] = start - i;
}
}
return result;
}
private static int[] order(double[] array, boolean decreasing) {
int size = array.length;
int[] idx = new int[size];
double[] baseArr = new double[size];
for (int i = 0; i < size; ++i) {
baseArr[i] = array[i];
idx[i] = i;
}
Comparator<Integer> cmp;
if (!decreasing) {
cmp = Comparator.comparingDouble(a -> baseArr[a]);
} else {
cmp = (a, b) -> Double.compare(baseArr[b], baseArr[a]);
}
return Arrays.stream(idx)
.boxed()
.sorted(cmp)
.mapToInt(a -> a)
.toArray();
}
private static double[] cummin(double[] array) {
if (array.length < 1) throw new IllegalArgumentException("cummin requires at least one element");
double[] output = new double[array.length];
double cumulativeMin = array[0];
for (int i = 0; i < array.length; ++i) {
if (array[i] < cumulativeMin) cumulativeMin = array[i];
output[i] = cumulativeMin;
}
return output;
}
private static double[] cummax(double[] array) {
if (array.length < 1) throw new IllegalArgumentException("cummax requires at least one element");
double[] output = new double[array.length];
double cumulativeMax = array[0];
for (int i = 0; i < array.length; ++i) {
if (array[i] > cumulativeMax) cumulativeMax = array[i];
output[i] = cumulativeMax;
}
return output;
}
private static double[] pminx(double[] array, double x) {
if (array.length < 1) throw new IllegalArgumentException("pmin requires at least one element");
double[] result = new double[array.length];
for (int i = 0; i < array.length; ++i) {
if (array[i] < x) {
result[i] = array[i];
} else {
result[i] = x;
}
}
return result;
}
private static void doubleSay(double[] array) {
System.out.printf("[ 1] %e", array[0]);
for (int i = 1; i < array.length; ++i) {
System.out.printf(" %.10f", array[i]);
if ((i + 1) % 5 == 0) System.out.printf("\n[%2d]", i + 1);
}
System.out.println();
}
private static double[] intToDouble(int[] array) {
double[] result = new double[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = array[i];
}
return result;
}
private static double doubleArrayMin(double[] array) {
if (array.length < 1) throw new IllegalArgumentException("pAdjust requires at least one element");
return Arrays.stream(array).min().orElse(Double.NaN);
}
private static double[] pAdjust(double[] pvalues, String str) {
int size = pvalues.length;
if (size < 1) throw new IllegalArgumentException("pAdjust requires at least one element");
int type;
switch (str.toLowerCase()) {
case "bh":
case "fdr":
type = 0;
break;
case "by":
type = 1;
break;
case "bonferroni":
type = 2;
break;
case "hochberg":
type = 3;
break;
case "holm":
type = 4;
break;
case "hommel":
type = 5;
break;
default:
throw new IllegalArgumentException(str + " doesn't match any accepted FDR types");
}
if (type == 2) { // Bonferroni method
double[] result = new double[size];
for (int i = 0; i < size; ++i) {
double b = pvalues[i] * size;
if (b >= 1) {
result[i] = 1;
} else if (0 <= b && b < 1) {
result[i] = b;
} else {
throw new RuntimeException("" + b + " is outside [0, 1)");
}
}
return result;
} else if (type == 4) { // Holm method
int[] o = order(pvalues, false);
double[] o2Double = intToDouble(o);
double[] cummaxInput = new double[size];
for (int i = 0; i < size; ++i) {
cummaxInput[i] = (size - i) * pvalues[o[i]];
}
int[] ro = order(o2Double, false);
double[] cummaxOutput = cummax(cummaxInput);
double[] pmin = pminx(cummaxOutput, 1.0);
double[] result = new double[size];
for (int i = 0; i < size; ++i) {
result[i] = pmin[ro[i]];
}
return result;
} else if (type == 5) {
int[] indices = seqLen(size, size);
int[] o = order(pvalues, false);
double[] p = new double[size];
for (int i = 0; i < size; ++i) {
p[i] = pvalues[o[i]];
}
double[] o2Double = intToDouble(o);
int[] ro = order(o2Double, false);
double[] q = new double[size];
double[] pa = new double[size];
double[] npi = new double[size];
for (int i = 0; i < size; ++i) {
npi[i] = p[i] * size / indices[i];
}
double min = doubleArrayMin(npi);
Arrays.fill(q, min);
Arrays.fill(pa, min);
for (int j = size; j >= 2; --j) {
int[] ij = seqLen(1, size - j + 1);
for (int i = 0; i < size - j + 1; ++i) {
ij[i]--;
}
int i2Length = j - 1;
int[] i2 = new int[i2Length];
for (int i = 0; i < i2Length; ++i) {
i2[i] = size - j + 2 + i - 1;
}
double q1 = j * p[i2[0]] / 2.0;
for (int i = 1; i < i2Length; ++i) {
double temp_q1 = p[i2[i]] * j / (2.0 + i);
if (temp_q1 < q1) q1 = temp_q1;
}
for (int i = 0; i < size - j + 1; ++i) {
q[ij[i]] = Math.min(p[ij[i]] * j, q1);
}
for (int i = 0; i < i2Length; ++i) {
q[i2[i]] = q[size - j];
}
for (int i = 0; i < size; ++i) {
if (pa[i] < q[i]) {
pa[i] = q[i];
}
}
}
for (int i = 0; i < size; ++i) {
q[i] = pa[ro[i]];
}
return q;
}
double[] ni = new double[size];
int[] o = order(pvalues, true);
double[] oDouble = intToDouble(o);
for (int i = 0; i < size; ++i) {
if (pvalues[i] < 0 || pvalues[i] > 1) {
throw new RuntimeException("array[" + i + "] = " + pvalues[i] + " is outside [0, 1]");
}
ni[i] = (double) size / (size - i);
}
int[] ro = order(oDouble, false);
double[] cumminInput = new double[size];
if (type == 0) { // BH method
for (int i = 0; i < size; ++i) {
cumminInput[i] = ni[i] * pvalues[o[i]];
}
} else if (type == 1) { // BY method
double q = 0;
for (int i = 1; i < size + 1; ++i) {
q += 1.0 / i;
}
for (int i = 0; i < size; ++i) {
cumminInput[i] = q * ni[i] * pvalues[o[i]];
}
} else if (type == 3) { // Hochberg method
for (int i = 0; i < size; ++i) {
cumminInput[i] = (i + 1) * pvalues[o[i]];
}
}
double[] cumminArray = cummin(cumminInput);
double[] pmin = pminx(cumminArray, 1.0);
double[] result = new double[size];
for (int i = 0; i < size; ++i) {
result[i] = pmin[ro[i]];
}
return result;
}
public static void main(String[] args) {
double[] pvalues = new double[]{
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
};
double[][] correctAnswers = new double[][]{
new double[]{ // Benjamini-Hochberg
6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02
},
new double[]{ // Benjamini & Yekutieli
1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02
},
new double[]{ // Bonferroni
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01
},
new double[]{ // Hochberg
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
},
new double[]{ // Holm
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
},
new double[]{ // Hommel
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01
}
};
String[] types = new String[]{"bh", "by", "bonferroni", "hochberg", "holm", "hommel"};
for (int type = 0; type < types.length; ++type) {
double[] q = pAdjust(pvalues, types[type]);
double error = 0.0;
for (int i = 0; i < pvalues.length; ++i) {
error += Math.abs(q[i] - correctAnswers[type][i]);
}
doubleSay(q);
System.out.printf("\ntype %d = '%s' has a cumulative error of %g\n", type, types[type], error);
}
}
}

View file

@ -0,0 +1,25 @@
using MultipleTesting, IterTools, Printf
p = [4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03]
function printpvalues(v)
for chunk in partition(v, 10)
println(join((@sprintf("%4.7f", p) for p in chunk), ", "))
end
end
println("Original p-values:")
printpvalues(p)
for corr in (Bonferroni(), BenjaminiHochberg(), BenjaminiYekutieli(), Holm(), Hochberg(), Hommel())
println("\n", corr)
printpvalues(adjust(p, corr))
end

View file

@ -0,0 +1,282 @@
// version 1.1.51
import java.util.Arrays
typealias IAE = IllegalArgumentException
fun seqLen(start: Int, end: Int) =
when {
start == end -> IntArray(end + 1) { it + 1 }
start < end -> IntArray(end - start + 1) { start + it }
else -> IntArray(start - end + 1) { start - it }
}
var baseArr: DoubleArray? = null
fun compareIncrease(a: Int, b: Int): Int = baseArr!![b].compareTo(baseArr!![a])
fun compareDecrease(a: Int, b: Int): Int = baseArr!![a].compareTo(baseArr!![b])
fun order(array: DoubleArray, decreasing: Boolean): IntArray {
val size = array.size
var idx = IntArray(size) { it }
baseArr = array.copyOf()
if (!decreasing) {
idx = Arrays.stream(idx)
.boxed()
.sorted { a, b -> compareDecrease(a, b) }
.mapToInt { it }
.toArray()
}
else {
idx = Arrays.stream(idx)
.boxed()
.sorted { a, b -> compareIncrease(a, b) }
.mapToInt { it }
.toArray()
}
baseArr = null
return idx
}
fun cummin(array: DoubleArray): DoubleArray {
val size = array.size
if (size < 1) throw IAE("cummin requires at least one element")
val output = DoubleArray(size)
var cumulativeMin = array[0]
for (i in 0 until size) {
if (array[i] < cumulativeMin) cumulativeMin = array[i]
output[i] = cumulativeMin
}
return output
}
fun cummax(array: DoubleArray): DoubleArray {
val size = array.size
if (size < 1) throw IAE("cummax requires at least one element")
val output = DoubleArray(size)
var cumulativeMax = array[0]
for (i in 0 until size) {
if (array[i] > cumulativeMax) cumulativeMax = array[i]
output[i] = cumulativeMax
}
return output
}
fun pminx(array: DoubleArray, x: Double): DoubleArray {
val size = array.size
if (size < 1) throw IAE("pmin requires at least one element")
return DoubleArray(size) { if (array[it] < x) array[it] else x }
}
fun doubleSay(array: DoubleArray) {
print("[ 1] %e".format(array[0]))
for (i in 1 until array.size) {
print(" %.10f".format(array[i]))
if ((i + 1) % 5 == 0) print("\n[%2d]".format(i + 1))
}
println()
}
fun intToDouble(array: IntArray) = DoubleArray(array.size) { array[it].toDouble() }
fun doubleArrayMin(array: DoubleArray) =
if (array.size < 1) throw IAE("pAdjust requires at least one element")
else array.min()!!
fun pAdjust(pvalues: DoubleArray, str: String): DoubleArray {
val size = pvalues.size
if (size < 1) throw IAE("pAdjust requires at least one element")
val type = when(str.toLowerCase()) {
"bh", "fdr" -> 0
"by" -> 1
"bonferroni" -> 2
"hochberg" -> 3
"holm" -> 4
"hommel" -> 5
else -> throw IAE("'$str' doesn't match any accepted FDR types")
}
if (type == 2) { // Bonferroni method
return DoubleArray(size) {
val b = pvalues[it] * size
when {
b >= 1 -> 1.0
0 <= b && b < 1 -> b
else -> throw RuntimeException("$b is outside [0, 1)")
}
}
}
else if (type == 4) { // Holm method
val o = order(pvalues, false)
val o2Double = intToDouble(o)
val cummaxInput = DoubleArray(size) { (size - it) * pvalues[o[it]] }
val ro = order(o2Double, false)
val cummaxOutput = cummax(cummaxInput)
val pmin = pminx(cummaxOutput, 1.0)
return DoubleArray(size) { pmin[ro[it]] }
}
else if (type == 5) { // Hommel method
val indices = seqLen(size, size)
val o = order(pvalues, false)
val p = DoubleArray(size) { pvalues[o[it]] }
val o2Double = intToDouble(o)
val ro = order(o2Double, false)
val q = DoubleArray(size)
val pa = DoubleArray(size)
val npi = DoubleArray(size) { p[it] * size / indices[it] }
val min = doubleArrayMin(npi)
q.fill(min)
pa.fill(min)
for (j in size - 1 downTo 2) {
val ij = seqLen(1, size - j + 1)
for (i in 0 until size - j + 1) ij[i]--
val i2Length = j - 1
val i2 = IntArray(i2Length) { size - j + 2 + it - 1 }
val pi2Length = i2Length
var q1 = j * p[i2[0]] / 2.0
for (i in 1 until pi2Length) {
val temp_q1 = p[i2[i]] * j / (2.0 + i)
if(temp_q1 < q1) q1 = temp_q1
}
for (i in 0 until size - j + 1) {
q[ij[i]] = minOf(p[ij[i]] * j, q1)
}
for (i in 0 until i2Length) q[i2[i]] = q[size - j]
for (i in 0 until size) if (pa[i] < q[i]) pa[i] = q[i]
}
for (index in 0 until size) q[index] = pa[ro[index]]
return q
}
val ni = DoubleArray(size)
val o = order(pvalues, true)
val oDouble = intToDouble(o)
for (index in 0 until size) {
if (pvalues[index] !in 0.0 .. 1.0) {
throw RuntimeException("array[$index] = ${pvalues[index]} is outside [0, 1]")
}
ni[index] = size.toDouble() / (size - index)
}
val ro = order(oDouble, false)
val cumminInput = DoubleArray(size)
if (type == 0) { // BH method
for (index in 0 until size) {
cumminInput[index] = ni[index] * pvalues[o[index]]
}
}
else if (type == 1) { // BY method
var q = 0.0
for (index in 1 until size + 1) q += 1.0 / index
for (index in 0 until size) {
cumminInput[index] = q * ni[index] * pvalues[o[index]]
}
}
else if (type == 3) { // Hochberg method
for (index in 0 until size) {
cumminInput[index] = (index + 1) * pvalues[o[index]]
}
}
val cumminArray = cummin(cumminInput)
val pmin = pminx(cumminArray, 1.0)
return DoubleArray(size) { pmin[ro[it]] }
}
fun main(args: Array<String>) {
val pvalues = doubleArrayOf(
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
)
val correctAnswers = listOf(
doubleArrayOf( // Benjamini-Hochberg
6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02
),
doubleArrayOf( // Benjamini & Yekutieli
1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02
),
doubleArrayOf( // Bonferroni
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01
),
doubleArrayOf( // Hochberg
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
),
doubleArrayOf( // Holm
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01
),
doubleArrayOf( // Hommel
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01
)
)
val types = listOf("bh", "by", "bonferroni", "hochberg", "holm", "hommel")
val f = "\ntype %d = '%s' has cumulative error of %g"
for (type in 0 until types.size) {
val q = pAdjust(pvalues, types[type])
var error = 0.0
for (i in 0 until pvalues.size) {
error += Math.abs(q[i] - correctAnswers[type][i])
}
doubleSay(q)
println(f.format(type, types[type], error))
}
}

View file

@ -0,0 +1,146 @@
// version 1.2.21
typealias DList = List<Double>
enum class Direction { UP, DOWN }
// test also for 'Unknown' correction type
val types = listOf(
"Benjamini-Hochberg", "Benjamini-Yekutieli", "Bonferroni", "Hochberg",
"Holm", "Hommel", "Šidák", "Unknown"
)
fun adjusted(p: DList, type: String) = "\n$type\n${pFormat(adjust(check(p), type))}"
fun pFormat(p: DList, cols: Int = 5): String {
var i = -cols
val fmt = "%1.10f"
return p.chunked(cols).map { chunk ->
i += cols
"[%2d] %s".format(i, chunk.map { fmt.format(it) }.joinToString(" "))
}.joinToString("\n")
}
fun check(p: DList): DList {
require(p.size > 0 && p.min()!! >= 0.0 && p.max()!! <= 1.0) {
"p-values must be in range 0.0 to 1.0"
}
return p
}
fun ratchet(p: DList, dir: Direction): DList {
val pp = p.toMutableList()
var m = pp[0]
if (dir == Direction.UP) {
for (i in 1 until pp.size) {
if (pp[i] > m) pp[i] = m
m = pp[i]
}
}
else {
for (i in 1 until pp.size) {
if (pp[i] < m) pp[i] = m
m = pp[i]
}
}
return pp.map { if (it < 1.0) it else 1.0 }
}
fun schwartzian(p: DList, mult: DList, dir: Direction): DList {
val size = p.size
val order = if (dir == Direction.UP)
p.withIndex().sortedByDescending { it.value }.map { it.index }
else
p.withIndex().sortedBy { it.value }.map { it.index }
var pa = List(size) { mult[it] * p[order[it]] }
pa = ratchet(pa, dir)
val order2 = order.withIndex().sortedBy{ it.value }.map { it.index }
return List(size) { pa[order2[it]] }
}
fun adjust(p: DList, type: String): DList {
val size = p.size
require(size > 0)
when (type) {
"Benjamini-Hochberg" -> {
val mult = List(size) { size.toDouble() / (size - it) }
return schwartzian(p, mult, Direction.UP)
}
"Benjamini-Yekutieli" -> {
val q = (1..size).sumByDouble { 1.0 / it }
val mult = List(size) { q * size / (size - it) }
return schwartzian(p, mult, Direction.UP)
}
"Bonferroni" -> {
return p.map { minOf(it * size, 1.0) }
}
"Hochberg" -> {
val mult = List(size) { (it + 1).toDouble() }
return schwartzian(p, mult, Direction.UP)
}
"Holm" -> {
val mult = List(size) { (size - it).toDouble() }
return schwartzian(p, mult, Direction.DOWN)
}
"Hommel" -> {
val order = p.withIndex().sortedBy { it.value }.map { it.index }
val s = List(size) { p[order[it]] }
val min = List(size){ s[it] * size / ( it + 1) }.min()!!
val q = MutableList(size) { min }
val pa = MutableList(size) { min }
for (j in size - 1 downTo 2) {
val lower = IntArray(size - j + 1) { it } // lower indices
val upper = IntArray(j - 1) { size - j + 1 + it } // upper indices
var qmin = j * s[upper[0]] / 2.0
for (i in 1 until upper.size) {
val temp = s[upper[i]] * j / (2.0 + i)
if (temp < qmin) qmin = temp
}
for (i in 0 until lower.size) {
q[lower[i]] = minOf(s[lower[i]] * j, qmin)
}
for (i in 0 until upper.size) q[upper[i]] = q[size - j]
for (i in 0 until size) if (pa[i] < q[i]) pa[i] = q[i]
}
val order2 = order.withIndex().sortedBy{ it.value }.map { it.index }
return List(size) { pa[order2[it]] }
}
"Šidák" -> {
val m = size.toDouble()
return p.map { 1.0 - Math.pow(1.0 - it, m) }
}
else -> {
println(
"\nSorry, do not know how to do '$type' correction.\n" +
"Perhaps you want one of these?:\n" +
types.dropLast(1).map { " $it" }.joinToString("\n")
)
System.exit(1)
}
}
return p
}
fun main(args: Array<String>) {
val pValues = listOf(
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
)
types.forEach { println(adjusted(pValues, it)) }
}

View file

@ -0,0 +1,155 @@
import algorithm, math, sequtils, strformat, strutils, sugar
type
CorrectionType {.pure.} = enum
BenjaminiHochberg = "Benjamini-Hochberg"
BenjaminiYekutieli = "Benjamini-Yekutieli"
Bonferroni = "Bonferroni"
Hochberg = "Hochberg"
Holm = "Holm"
Hommel = "Hommel"
Šidák = "Šidák"
Direction {.pure.} = enum Up, Down
PValues = seq[float]
template newPValues(length: Natural): PValues =
## Create a PValues object of given length.
newSeq[float](length)
func ratchet(p: var PValues; dir: Direction) =
var m = p[0]
case dir
of Up:
for i in 1..p.high:
if p[i] > m: p[i] = m
m = p[i]
of Down:
for i in 1..p.high:
if p[i] < m: p[i] = m
m = p[i]
for i in 0..p.high:
if p[i] > 1: p[i] = 1
func schwartzian(p, mult: PValues; dir: Direction): PValues =
let length = p.len
let sortOrder = if dir == Up: Descending else: Ascending
let order1 = toSeq(p.pairs).sorted((x, y) => cmp(x.val, y.val), sortOrder).mapIt(it.key)
var pa = newPValues(length)
for i in 0..pa.high:
pa[i] = mult[i] * p[order1[i]]
ratchet(pa, dir)
let order2 = toSeq(order1.pairs).sortedByIt(it.val).mapIt(it.key)
for idx in order2:
result.add pa[idx]
proc adjust(p: PValues; ctype: CorrectionType): PValues =
let length = p.len
assert length > 0
let flength = length.toFloat
case ctype
of BenjaminiHochberg:
var mult = newPValues(length)
for i in 0..mult.high:
mult[i] = flength / (flength - i.toFloat)
return schwartzian(p, mult, Up)
of BenjaminiYekutieli:
var q = 0.0
for i in 1..length: q += 1 / i
var mult = newPValues(length)
for i in 0..mult.high:
mult[i] = (q * flength) / (flength - i.toFloat)
return schwartzian(p, mult, Up)
of Bonferroni:
result = newPValues(length)
for i in 0..result.high:
result[i] = min(p[i] * flength, 1)
return
of Hochberg:
var mult = newPValues(length)
for i in 0..mult.high:
mult[i] = i.toFloat + 1
return schwartzian(p, mult, Up)
of Holm:
var mult = newPValues(length)
for i in 0..mult.high:
mult[i] = flength - i.toFloat
return schwartzian(p, mult, Down)
of Hommel:
let order1 = toSeq(p.pairs).sortedByIt(it.val).mapIt(it.key)
let s = order1.mapIt(p[it])
var m = Inf
for i in 0..s.high:
m = min(m, s[i] * flength / (i + 1).toFloat)
var q, pa = repeat(m, length)
for j in countdown(length - 1, 2):
let lower = toSeq(0..length - j)
let upper = toSeq((length - j + 1)..<length)
var qmin = j.toFloat * s[upper[0]] / 2
for i in 1..upper.high:
let val = s[upper[i]] * j.toFloat / (i + 2).toFloat
if val < qmin: qmin = val
for idx in lower: q[idx] = min(s[idx] * j.toFloat, qmin)
for idx in upper: q[idx] = q[^j]
for i, val in q:
if pa[i] < val: pa[i] = val
let order2 = toSeq(order1.pairs).sortedByIt(it.val).mapIt(it.key)
return order2.mapIt(pa[it])
of Šidák:
result = newPValues(length)
for i in 0..result.high:
result[i] = 1 - (1 - p[i])^length
return
func pformat(p: PValues; cols = 5): string =
var lines: seq[string]
for i in countup(0, p.high, cols):
let fchunk = p[i..<(i + cols)]
var schunk = newSeq[string](fchunk.len)
for j in 0..<cols:
schunk[j] = fchunk[j].formatFloat(ffDecimal, 10)
lines.add &"[{i:2}] {schunk.join(\" \")}"
result = lines.join("\n")
func adjusted(p: PValues; ctype: CorrectionType): string =
doAssert p.len > 0 and min(p) >= 0 and max(p) <= 1, "p-values must be in range 0.0 to 1.0."
result = &"\n{ctype}\n{pformat(p.adjust(ctype))}"
when isMainModule:
const PVals = @[
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03]
for ctype in CorrectionType:
echo adjusted(PVals, ctype)

View file

@ -0,0 +1,310 @@
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use autodie ':all';
use List::Util 'min';
use feature 'say';
sub pmin {
my $array = shift;
my $x = 1;
my @pmin_array;
my $n = scalar @$array;
for (my $index = 0; $index < $n; $index++) {
$pmin_array[$index] = min(@$array[$index], $x);
}
@pmin_array
}
sub cummin {
my $array_ref = shift;
my @cummin;
my $cumulative_min = @$array_ref[0];
foreach my $p (@$array_ref) {
if ($p < $cumulative_min) {
$cumulative_min = $p;
}
push @cummin, $cumulative_min;
}
@cummin
}
sub cummax {
my $array_ref = shift;
my @cummax;
my $cumulative_max = @$array_ref[0];
foreach my $p (@$array_ref) {
if ($p > $cumulative_max) {
$cumulative_max = $p;
}
push @cummax, $cumulative_max;
}
@cummax
}
sub order {#made to match R's "order"
my $array_ref = shift;
my $decreasing = 'false';
if (defined $_[0]) {
my $option = shift;
if ($option =~ m/true/i) {
$decreasing = 'true';
} elsif ($option =~ m/false/i) {
#do nothing, it's already set to false
} else {
print "2nd option should only be case-insensitive 'true' or 'false'";
die;
}
}
my @array;
my $max_index = scalar @$array_ref-1;
if ($decreasing eq 'false') {
@array = sort { @$array_ref[$a] <=> @$array_ref[$b] } 0..$max_index;
} elsif ($decreasing eq 'true') {
@array = sort { @$array_ref[$b] <=> @$array_ref[$a] } 0..$max_index;
}
@array
}
sub p_adjust {
my $pvalues_ref = shift;
my $method;
if (defined $_[0]) {
$method = shift
} else {
$method = 'Holm'
}
my %methods = (
'bh' => 1,
'fdr' => 1,
'by' => 1,
'holm' => 1,
'hommel' => 1,
'bonferroni' => 1,
'hochberg' => 1
);
my $method_found = 'no';
foreach my $key (keys %methods) {
if ((uc $method) eq (uc $key)) {
$method = $key;
$method_found = 'yes';
last
}
}
if ($method_found eq 'no') {
if ($method =~ m/benjamini-?\s*hochberg/i) {
$method = 'bh';
$method_found = 'yes';
} elsif ($method =~ m/benjamini-?\s*yekutieli/i) {
$method = 'by';
$method_found = 'yes';
}
}
if ($method_found eq 'no') {
print "No method could be determined from $method.\n";
die
}
my $lp = scalar @$pvalues_ref;
my $n = $lp;
my @qvalues;
if ($method eq 'hochberg') {
my @o = order($pvalues_ref, 'TRUE');
my @cummin_input;
for (my $index = 0; $index < $n; $index++) {
$cummin_input[$index] = ($index+1)* @$pvalues_ref[$o[$index]];#PVALUES[$o[$index]] is p[o]
}
my @cummin = cummin(\@cummin_input);
my @pmin = pmin(\@cummin);
my @ro = order(\@o);
@qvalues = @pmin[@ro];
} elsif ($method eq 'bh') {
my @o = order($pvalues_ref, 'TRUE');
my @cummin_input;
for (my $index = 0; $index < $n; $index++) {
$cummin_input[$index] = ($n/($n-$index))* @$pvalues_ref[$o[$index]];#PVALUES[$o[$index]] is p[o]
}
my @ro = order(\@o);
my @cummin = cummin(\@cummin_input);
my @pmin = pmin(\@cummin);
@qvalues = @pmin[@ro];
} elsif ($method eq 'by') {
my $q = 0.0;
my @o = order($pvalues_ref, 'TRUE');
my @ro = order(\@o);
for (my $index = 1; $index < ($n+1); $index++) {
$q += 1.0 / $index;
}
my @cummin_input;
for (my $index = 0; $index < $n; $index++) {
$cummin_input[$index] = $q * ($n/($n-$index)) * @$pvalues_ref[$o[$index]];#PVALUES[$o[$index]] is p[o]
}
# say join (',', @cummin_input);
# say '@cummin_input # of elements = ' . scalar @cummin_input;
my @cummin = cummin(\@cummin_input);
undef @cummin_input;
my @pmin = pmin(\@cummin);
@qvalues = @pmin[@ro];
} elsif ($method eq 'bonferroni') {
for (my $index = 0; $index < $n; $index++) {
my $q = @$pvalues_ref[$index]*$n;
if ((0 <= $q) && ($q < 1)) {
$qvalues[$index] = $q;
} elsif ($q >= 1) {
$qvalues[$index] = 1.0;
} else {
say 'Failed to get Bonferroni adjusted p.';
die;
}
}
} elsif ($method eq 'holm') {
my @o = order($pvalues_ref);
my @cummax_input;
for (my $index = 0; $index < $n; $index++) {
$cummax_input[$index] = ($n - $index) * @$pvalues_ref[$o[$index]];
}
my @ro = order(\@o);
undef @o;
my @cummax = cummax(\@cummax_input);
undef @cummax_input;
my @pmin = pmin(\@cummax);
undef @cummax;
@qvalues = @pmin[@ro];
} elsif ($method eq 'hommel') {
my @o = order($pvalues_ref);
my @p = @$pvalues_ref[@o];
my @ro = order(\@o);
undef @o;
my (@q, @pa);
my $min = $n*$p[0];
for (my $index = 0; $index < $n; $index++) {
my $temp = $n*$p[$index] / ($index + 1);
$min = min($min, $temp);
}
for (my $index = 0; $index < $n; $index++) {
$pa[$index] = $min;#q <- pa <- rep.int(min(n * p/i), n)
$q[$index] = $min;#q <- pa <- rep.int(min(n * p/i), n)
}
for (my $j = ($n-1); $j >= 2; $j--) {
my @ij = 0..($n - $j);#ij <- seq_len(n - j + 1)
my $I2_LENGTH = $j - 1;
my @i2;
for (my $i = 0; $i < $I2_LENGTH; $i++) {
$i2[$i] = $n-$j+2+$i-1;
#R's indices are 1-based, C's are 0-based, I added the -1
}
my $q1 = $j * $p[$i2[0]] / 2.0;
for (my $i = 1; $i < $I2_LENGTH; $i++) {#loop through 2:j
my $TEMP_Q1 = $j * $p[$i2[$i]] / (2 + $i);
$q1 = min($TEMP_Q1, $q1);
}
for (my $i = 0; $i < ($n - $j + 1); $i++) {#q[ij] <- pmin(j * p[ij], q1)
$q[$ij[$i]] = min( $j*$p[$ij[$i]], $q1);
}
for (my $i = 0; $i < $I2_LENGTH; $i++) {#q[i2] <- q[n - j + 1]
$q[$i2[$i]] = $q[$n - $j];
}
for (my $i = 0; $i < $n; $i++) {#pa <- pmax(pa, q)
if ($pa[$i] < $q[$i]) {
$pa[$i] = $q[$i];
}
}
# printf("j = %zu, pa = \n", j);
# double_say(pa, N);
}#end j loop
@qvalues = @pa[@ro];
} else {
print "$method doesn't fit my types.\n";
die
}
@qvalues
}
my @pvalues = (4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03);
my %correct_answers = (
'Benjamini-Hochberg' => [6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02],
'Benjamini-Yekutieli' => [1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02],
'Bonferroni' => [1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01],
'Hochberg' => [9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01],
'Holm' => [1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01],
'Hommel' => [9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01]);
foreach my $method ('Hochberg','Benjamini-Hochberg','Benjamini-Yekutieli', 'Bonferroni', 'Holm', 'Hommel') {
print "$method\n";
my @qvalues = p_adjust(\@pvalues, $method);
my $error = 0.0;
foreach my $q (0..$#qvalues) {
$error += abs($qvalues[$q] - $correct_answers{$method}[$q]);
}
printf("type $method has cumulative error of %g.\n", $error);
}

View file

@ -0,0 +1,195 @@
(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">enum</span> <span style="color: #000000;">UP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">DOWN</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">ratchet</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">=</span><span style="color: #000000;">UP</span><span style="color: #0000FF;">?</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]></span><span style="color: #000000;">m</span><span style="color: #0000FF;">:</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">m</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sq_min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">schwartzian</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mult</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">order</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">=</span><span style="color: #000000;">UP</span> <span style="color: #008080;">then</span> <span style="color: #000000;">order</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">reverse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">order</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">pa</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ratchet</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mult</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">extract</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">order</span><span style="color: #0000FF;">)),</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">extract</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pa</span><span style="color: #0000FF;">,</span><span style="color: #000000;">order</span><span style="color: #0000FF;">,</span><span style="color: #000000;">invert</span><span style="color: #0000FF;">:=</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">adjust</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">method</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">size</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">mult</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">switch</span> <span style="color: #000000;">method</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Benjamini-Hochberg"</span><span style="color: #0000FF;">:</span>
<span style="color: #000000;">mult</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_div</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mult</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">schwartzian</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mult</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">UP</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Benjamini-Yekutieli"</span><span style="color: #0000FF;">:</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_div</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mult</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">mult</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_div</span><span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">*</span><span style="color: #000000;">size</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mult</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">schwartzian</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mult</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">UP</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Bonferroni"</span><span style="color: #0000FF;">:</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sq_min</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">size</span><span style="color: #0000FF;">),</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Hochberg"</span><span style="color: #0000FF;">:</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">schwartzian</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mult</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">UP</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Holm"</span><span style="color: #0000FF;">:</span>
<span style="color: #000000;">mult</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mult</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">schwartzian</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mult</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">DOWN</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Hommel"</span><span style="color: #0000FF;">:</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ivdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">size</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">size</span> <span style="color: #008080;">do</span> <span style="color: #000000;">ivdx</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">i</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">ivdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ivdx</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ivdx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_div</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">size</span><span style="color: #0000FF;">),</span><span style="color: #000000;">mult</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">qh</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">),</span><span style="color: #000000;">size</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">pa</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">),</span><span style="color: #000000;">size</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">order</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ivdx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">size</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">2</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lwr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">-</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">upr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">size</span><span style="color: #0000FF;">-</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">j</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">qmin</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">*</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">upr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]]/</span><span style="color: #000000;">2</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">upr</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">qmin</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">upr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]*</span><span style="color: #000000;">j</span><span style="color: #0000FF;">/(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #000000;">qmin</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lwr</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">qh</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lwr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lwr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]*</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">qmin</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">upr</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">qh</span><span style="color: #0000FF;">[</span><span style="color: #000000;">upr</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">qh</span><span style="color: #0000FF;">[</span><span style="color: #000000;">size</span><span style="color: #0000FF;">-</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">pa</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pa</span><span style="color: #0000FF;">,</span><span style="color: #000000;">qh</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">extract</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pa</span><span style="color: #0000FF;">,</span><span style="color: #000000;">order</span><span style="color: #0000FF;">,</span><span style="color: #000000;">invert</span><span style="color: #0000FF;">:=</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"Sidak"</span><span style="color: #0000FF;">:</span>
<span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #0000FF;">-</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">-</span><span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">size</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">p</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- (unknown method)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">p</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">types</span><span style="color: #0000FF;">,</span><span style="color: #000000;">correct_answers</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">({</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Benjamini-Hochberg"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">6.126681e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.521710e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.987205e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.891595e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.217789e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.301450e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.870370e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.301450e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.049731e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.826753e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">6.482629e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.253722e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.280973e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.769926e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.705703e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.241867e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.049731e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.856107e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.887526e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.136717e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">4.991891e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.769926e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.217789e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.301450e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">2.304958e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.832475e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.899547e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.521710e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.476843e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.683638e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.562902e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.516084e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.250189e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.636589e-03</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">2.562902e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.946883e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.166064e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.899547e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.688991e-03</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">4.502862e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.252228e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.881555e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.142613e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.846527e-03</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">2.562902e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.846527e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.101708e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.252032e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.205958e-02</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Benjamini-Yekutieli"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.940844e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.510676e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.114323e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.754486e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.644618e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">7.575031e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.153102e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.581959e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.812089e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.636176e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.153102e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.325863e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.774239e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.754486e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.209832e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">2.025930e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.634031e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.546073e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.413926e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.180552e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.153102e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.180552e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.956812e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.262838e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.925057e-02</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Bonferroni"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.019185e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">2.020365e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.516674e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.625735e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.909271e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.537741e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.125636e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.782670e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.803480e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.882294e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.005725e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.252228e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.713920e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.395577e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.088915e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.846527e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.305125e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.867745e-01</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Hochberg"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.632662e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.575885e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.383967e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.938014e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.600230e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.501973e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.383967e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.052971e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.426136e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.626366e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.656419e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">8.825610e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.252228e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.930759e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.394022e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.692284e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.023581e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.974152e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.172920e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.992520e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.179486e-01</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Holm"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.632662e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.000000e+00</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.575885e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.395341e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.938014e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.600230e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.501973e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.395341e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.052971e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.426136e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.626366e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.656419e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">8.825610e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.252228e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.930759e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.394022e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.692284e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.023581e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.974152e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.172920e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.992520e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.179486e-01</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Hommel"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.987624e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.595180e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.351895e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.766522e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.414256e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.304340e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.530937e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.887709e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.385602e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.322457e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.722920e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.426136e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.218158e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.581127e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">8.825610e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.252228e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.743649e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.016908e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.516461e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">9.582456e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.877222e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.172920e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.122276e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.950067e-01</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Sidak"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9946598274</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9914285749</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9999515274</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9999999688</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9999999995</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9999998801</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9999999855</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9231179729</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">0.9999999956</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9999317605</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">0.9983109511</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.5068253940</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0000000000</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.9703301333</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">0.1832692440</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0150545753</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.4320729669</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.6993672225</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0286818157</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">0.0152621104</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.3391808707</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0656206307</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.4959194266</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0186503726</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">0.0009001752</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0000125222</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.8142104886</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.3772612062</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0430222116</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">0.0108312558</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0473319661</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0032997780</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.7705015898</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.2499384839</span><span style="color: #0000FF;">}}})</span>
<span style="color: #000080;font-style:italic;">-- {"Unknown",{1<nowiki>}}</nowiki>})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">pValues</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">4.533744e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.296024e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.936026e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.079658e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.801962e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">8.752257e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.922222e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.115421e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.355806e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.324867e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">4.926798e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.802978e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.485442e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.883130e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.729308e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">8.502518e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4.268138e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.442008e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.030266e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.001555e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">3.194810e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.892933e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.991834e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.745691e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.037516e-01</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.198578e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.966083e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.403837e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7.328671e-01</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.793476e-02</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">4.040730e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.033349e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.125147e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.375072e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.818542e-04</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">3.075482e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.251272e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.356534e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.360696e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.764588e-04</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">1.801145e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.504456e-07</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3.310253e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.427839e-03</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.791153e-04</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">2.177831e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.693054e-04</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6.610250e-05</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.900813e-02</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5.735490e-03</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pValues</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pValues</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pValues</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"p-values must be in range 0.0 to 1.0"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">types</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">types</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">adjust</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pValues</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">={}</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\nSorry, do not know how to do %s correction.\n"</span><span style="color: #0000FF;">&</span>
<span style="color: #008000;">"Perhaps you want one of these?:\n %s\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">types</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"\n "</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- printf(1,"%s\n",{ti})
-- res = correct_answers[i] -- (for easier comparison only)
-- pp(res,{pp_FltFmt,"%13.10f",pp_IntFmt,"%13.10f",pp_Maxlen,75,pp_Pause,0})</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_abs</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">correct_answers</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])))</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s has cumulative error of %g\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,</span><span style="color: #000000;">error</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--

View file

@ -0,0 +1,235 @@
from __future__ import division
import sys
def pminf(array):
x = 1
pmin_list = []
N = len(array)
for index in range(N):
if array[index] < x:
pmin_list.insert(index, array[index])
else:
pmin_list.insert(index, x)
return pmin_list
#end function
def cumminf(array):
cummin = []
cumulative_min = array[0]
for p in array:
if p < cumulative_min:
cumulative_min = p
cummin.append(cumulative_min)
return cummin
#end
def cummaxf(array):
cummax = []
cumulative_max = array[0]
for e in array:
if e > cumulative_max:
cumulative_max = e
cummax.append(cumulative_max)
return cummax
#end
def order(*args):
if len(args) > 1:
if args[1].lower() == 'false':# if ($string1 eq $string2) {
return sorted(range(len(args[0])), key = lambda k: args[0][k])
elif list(args[1].lower()) == list('true'):
return sorted(range(len(args[0])), key = lambda k: args[0][k], reverse = True)
else:
print "%s isn't a recognized parameter" % args[1]
sys.exit()
elif len(args) == 1:
return sorted(range(len(args[0])), key = lambda k: args[0][k])
#end
def p_adjust(*args):
method = "bh"
pvalues = args[0]
if len(args) > 1:
methods = {"bh", "fdr", "by", "holm", "hommel", "bonferroni", "hochberg"}
metharg = arg[1].lower()
if metharg in methods:
method = metharg
lp = len(pvalues)
n = lp
qvalues = []
if method == 'hochberg':#already all lower case
o = order(pvalues, 'TRUE')
cummin_input = []
for index in range(n):
cummin_input.insert(index, (index+1)*pvalues[o[index]])
cummin = cumminf(cummin_input)
pmin = pminf(cummin)
ro = order(o)
qvalues = [pmin[i] for i in ro]
elif method == 'bh':
o = order(pvalues, 'TRUE')
cummin_input = []
for index in range(n):
cummin_input.insert(index, (n/(n-index))* pvalues[o[index]])
ro = order(o)
cummin = cumminf(cummin_input)
pmin = pminf(cummin)
qvalues = [pmin[i] for i in ro]
elif method == 'by':
q = 0.0
o = order(pvalues, 'TRUE')
ro = order(o)
for index in range(1, n+1):
q += 1.0 / index;
cummin_input = []
for index in range(n):
cummin_input.insert(index, q * (n/(n-index)) * pvalues[o[index]])
cummin = cumminf(cummin_input)
pmin = pminf(cummin)
qvalues = [pmin[i] for i in ro]
elif method == 'bonferroni':
for index in range(n):
q = pvalues[index] * n
if (0 <= q) and (q < 1):
qvalues.insert(index, q)
elif q >= 1:
qvalues.insert(index, 1)
else:
print '%g won\'t give a Bonferroni adjusted p' % q
sys.exit()
elif method == 'holm':
o = order(pvalues)
cummax_input = []
for index in range(n):
cummax_input.insert(index, (n - index) * pvalues[o[index]])
ro = order(o)
cummax = cummaxf(cummax_input)
pmin = pminf(cummax)
qvalues = [pmin[i] for i in ro]
elif method == 'hommel':
i = range(1,n+1)
o = order(pvalues)
p = [pvalues[index] for index in o]
ro = order(o)
pa = []
q = []
smin = n*p[0]
for index in range(n):
temp = n*p[index] / (index + 1)
if temp < smin:
smin = temp
for index in range(n):
pa.insert(index, smin)
q.insert(index, smin)
for j in range(n-1,1,-1):
ij = range(1,n-j+2)
for x in range(len(ij)):
ij[x] -= 1
I2_LENGTH = j - 1
i2 = []
for index in range(I2_LENGTH+1):
i2.insert(index, n - j + 2 + index - 1)
q1 = j * p[i2[0]] / 2.0
for index in range(1,I2_LENGTH):
TEMP_Q1 = j * p[i2[index]] / (2.0 + index)
if TEMP_Q1 < q1:
q1 = TEMP_Q1
for index in range(n - j + 1):
q[ij[index]] = min(j * p[ij[index]], q1)
for index in range(I2_LENGTH):
q[i2[index]] = q[n-j]
for index in range(n):
if pa[index] < q[index]:
pa[index] = q[index]
qvalues = [pa[index] for index in ro]
else:
print "method %s isn't defined." % method
sys.exit()
return qvalues
pvalues = [4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03]
correct_answers = {}
correct_answers['bh'] = [6.126681e-01, 8.521710e-01, 1.987205e-01, 1.891595e-01, 3.217789e-01,
9.301450e-01, 4.870370e-01, 9.301450e-01, 6.049731e-01, 6.826753e-01,
6.482629e-01, 7.253722e-01, 5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01, 4.887526e-01, 1.136717e-01,
4.991891e-01, 8.769926e-01, 9.991834e-01, 3.217789e-01, 9.301450e-01,
2.304958e-01, 5.832475e-01, 3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02, 6.250189e-02, 3.636589e-03,
2.562902e-03, 2.946883e-02, 6.166064e-03, 3.899547e-02, 2.688991e-03,
4.502862e-04, 1.252228e-05, 7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03, 7.252032e-02, 2.205958e-02]
correct_answers['by'] = [1.000000e+00, 1.000000e+00, 8.940844e-01, 8.510676e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 5.114323e-01,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01, 2.812089e-01, 1.636176e-02,
1.153102e-02, 1.325863e-01, 2.774239e-02, 1.754486e-01, 1.209832e-02,
2.025930e-03, 5.634031e-05, 3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03, 3.262838e-01, 9.925057e-02]
correct_answers['bonferroni'] = [1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 7.019185e-01, 1.000000e+00, 1.000000e+00,
2.020365e-01, 1.516674e-02, 5.625735e-01, 1.000000e+00, 2.909271e-02,
1.537741e-02, 4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01, 4.395577e-02,
1.088915e-02, 4.846527e-02, 3.305125e-03, 1.000000e+00, 2.867745e-01]
correct_answers['hochberg'] = [9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.632662e-01, 9.991834e-01, 9.991834e-01,
1.575885e-01, 1.383967e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.383967e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01]
correct_answers['holm'] = [1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 4.632662e-01, 1.000000e+00, 1.000000e+00,
1.575885e-01, 1.395341e-02, 3.938014e-01, 7.600230e-01, 2.501973e-02,
1.395341e-02, 3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01, 3.692284e-02,
1.023581e-02, 3.974152e-02, 3.172920e-03, 8.992520e-01, 2.179486e-01]
correct_answers['hommel'] = [9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 4.351895e-01, 9.991834e-01, 9.766522e-01,
1.414256e-01, 1.304340e-02, 3.530937e-01, 6.887709e-01, 2.385602e-02,
1.322457e-02, 2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01, 3.516461e-02,
9.582456e-03, 3.877222e-02, 3.172920e-03, 8.122276e-01, 1.950067e-01]
for key in correct_answers.keys():
error = 0.0
q = p_adjust(pvalues, key)
for i in range(len(q)):
error += abs(q[i] - correct_answers[key][i])
print '%s error = %g' % (key.upper(), error)

View file

@ -0,0 +1,29 @@
p <- c(4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03)
p.adjust(p, method = 'BH')
print("Benjamini-Hochberg")
writeLines("\n")
p.adjust(p, method = 'BY')
print("Benjamini & Yekutieli")
writeLines("\n")
p.adjust(p, method = 'bonferroni')
print("Bonferroni")
writeLines("\n")
p.adjust(p, method = 'hochberg')
print("Hochberg")
writeLines("\n");
p.adjust(p, method = 'hommel')
writeLines("Hommel\n")

View file

@ -0,0 +1,94 @@
########################### Helper subs ###########################
sub adjusted (@p, $type) { "\n$type\n" ~ format adjust( check(@p), $type ) }
sub format ( @p, $cols = 5 ) {
my $i = -$cols;
my $fmt = "%1.10f";
join "\n", @p.rotor($cols, :partial).map:
{ sprintf "[%2d] { join ' ', $fmt xx $_ }", $i+=$cols, $_ };
}
sub check ( @p ) { die 'p-values must be in range 0.0 to 1.0' if @p.min < 0 or 1 < @p.max; @p }
multi ratchet ( 'up', @p ) { my $m; @p[$_] min= $m, $m = @p[$_] for ^@p; @p }
multi ratchet ( 'dn', @p ) { my $m; @p[$_] max= $m, $m = @p[$_] for ^@p .reverse; @p }
sub schwartzian ( @p, &transform, :$ratchet ) {
my @pa = @p.map( {[$_, $++]} ).sort( -*.[0] ).map: { [transform(.[0]), .[1]] };
@pa[*;0] = ratchet($ratchet, @pa»[0]);
@pa.sort( *.[1] )»[0]
}
############# The various p-value correction routines #############
multi adjust( @p, 'Benjamini-Hochberg' ) {
@p.&schwartzian: * * @p / (@p - $++) min 1, :ratchet('up')
}
multi adjust( @p, 'Benjamini-Yekutieli' ) {
my \r = ^@p .map( { 1 / ++$ } ).sum;
@p.&schwartzian: * * r * @p / (@p - $++) min 1, :ratchet('up')
}
multi adjust( @p, 'Hochberg' ) {
my \m = @p.max;
@p.&schwartzian: * * ++$ min m, :ratchet('up')
}
multi adjust( @p, 'Holm' ) {
@p.&schwartzian: * * ++$ min 1, :ratchet('dn')
}
multi adjust( @p, 'Šidák' ) {
@p.&schwartzian: 1 - (1 - *) ** ++$, :ratchet('dn')
}
multi adjust( @p, 'Bonferroni' ) {
@p.map: * * @p min 1
}
# Hommel correction can't be easily reduced to a one pass transform
multi adjust( @p, 'Hommel' ) {
my @s = @p.map( {[$_, $++]} ).sort: *.[0] ; # sorted
my \z = +@p; # array si(z)e
my @pa = @s»[0].map( * * z / ++$ ).min xx z; # p adjusted
my @q; # scratch array
for (1 ..^ z).reverse -> $i {
my @L = 0 .. z - $i; # lower indices
my @U = z - $i ^..^ z; # upper indices
my $q = @s[@U]»[0].map( { $_ * $i / (2 + $++) } ).min;
@q[@L] = @s[@L]»[0].map: { min $_ * $i, $q, @s[*-1][0] };
@pa = ^z .map: { max @pa[$_], @q[$_] }
}
@pa[@s[*;1].map( {[$_, $++]} ).sort( *.[0] )»[1]]
}
multi adjust ( @p, $unknown ) {
note "\nSorry, do not know how to do $unknown correction.\n" ~
"Perhaps you want one of these?:\n" ~
<Benjamini-Hochberg Benjamini-Yekutieli Bonferroni Hochberg
Holm Hommel Šidák>.join("\n");
exit
}
########################### The task ###########################
my @p-values =
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
;
for < Benjamini-Hochberg Benjamini-Yekutieli Bonferroni Hochberg Holm Hommel Šidák >
{
say adjusted @p-values, $_
}

View file

@ -0,0 +1,264 @@
def pmin(array)
x = 1
pmin_array = []
array.each_index do |i|
pmin_array[i] = [array[i], x].min
abort if pmin_array[i] > 1
end
pmin_array
end
def cummin(array)
cumulative_min = array[0]
arr_cummin = []
array.each do |p|
cumulative_min = [p, cumulative_min].min
arr_cummin.push(cumulative_min)
end
arr_cummin
end
def cummax(array)
cumulative_max = array[0]
arr_cummax = []
array.each do |p|
cumulative_max = [p, cumulative_max].max
arr_cummax.push(cumulative_max)
end
arr_cummax
end
# decreasing variable is optional
def order(array, decreasing = false)
if decreasing == false
array.sort.map { |n| array.index(n) }
else
array.sort.map { |n| array.index(n) }.reverse
end
end
def p_adjust(arr_pvalues, method = 'Holm')
lp = arr_pvalues.size
n = lp
if method.casecmp('hochberg').zero?
arr_o = order(arr_pvalues, true)
arr_cummin_input = []
(0..n).each do |index|
arr_cummin_input[index] = (index + 1) * arr_pvalues[arr_o[index].to_i]
end
arr_cummin = cummin(arr_cummin_input)
arr_pmin = pmin(arr_cummin)
arr_ro = order(arr_o)
return arr_pmin.values_at(*arr_ro)
elsif method.casecmp('bh').zero? || method.casecmp('benjamini-hochberg').zero?
arr_o = order(arr_pvalues, true)
arr_cummin_input = []
(0..(n - 1)).each do |i|
arr_cummin_input[i] = (n / (n - i).to_f) * arr_pvalues[arr_o[i]]
end
arr_ro = order(arr_o)
arr_cummin = cummin(arr_cummin_input)
arr_pmin = pmin(arr_cummin)
return arr_pmin.values_at(*arr_ro)
elsif method.casecmp('by').zero? || method.casecmp('benjamini-yekutieli').zero?
q = 0.0
arr_o = order(arr_pvalues, true)
arr_ro = order(arr_o)
(1..n).each do |index|
q += 1.0 / index
end
arr_cummin_input = []
(0..(n - 1)).each do |i|
arr_cummin_input[i] = q * (n / (n - i).to_f) * arr_pvalues[arr_o[i]]
end
arr_cummin = cummin(arr_cummin_input)
arr_pmin = pmin(arr_cummin)
return arr_pmin.values_at(*arr_ro)
elsif method.casecmp('bonferroni').zero?
arr_qvalues = []
(0..(n - 1)).each do |i|
q = arr_pvalues[i] * n
if (q >= 0) && (q < 1)
arr_qvalues[i] = q
elsif q >= 1
arr_qvalues[i] = 1.0
else
puts "Falied to get Bonferroni adjusted p for #{arr_pvalues[i]}"
end
end
return arr_qvalues
elsif method.casecmp('holm').zero?
o = order(arr_pvalues)
cummax_input = []
(0..(n - 1)).each do |index|
cummax_input[index] = (n - index) * arr_pvalues[o[index]]
end
ro = order(o)
arr_cummax = cummax(cummax_input)
arr_pmin = pmin(arr_cummax)
return arr_pmin.values_at(*ro)
elsif method.casecmp('hommel').zero?
o = order(arr_pvalues)
arr_p = arr_pvalues.values_at(*o)
ro = order(o)
q = []
pa = []
min = n * arr_p[0]
(0..(n - 1)).each do |index|
temp = n * arr_p[index] / (index + 1)
min = [min, temp].min
end
(0..(n - 1)).each do |index|
pa[index] = min
q[index] = min
end
j = n - 1
while j >= 2
ij = Array 0..(n - j)
i2_length = j - 1
i2 = []
(0..(i2_length - 1)).each do |i|
i2[i] = n - j + 2 + i - 1 # R's indices are 1-based, C's are 0-based
end
q1 = j * arr_p[i2[0]] / 2.0
(1..(i2_length - 1)).each do |i|
temp_q1 = j * arr_p[i2[i]] / (2 + i)
q1 = [temp_q1, q1].min
end
(0..(n - j)).each do |i|
tmp = j * arr_p[ij[i]]
q[ij[i]] = [tmp, q1].min
end
(0..(i2_length - 1)).each do |i|
q[i2[i]] = q[n - j]
end
(0..(n - 1)).each do |i|
pa[i] = q[i] if pa[i] < q[i]
end
j -= 1
end
return pa.values_at(*ro)
else
puts "#{method} isn't accepted."
abort
end
end
pvalues =
[4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02,
1.801962e-01, 8.752257e-01, 2.922222e-01, 9.115421e-01,
4.355806e-01, 5.324867e-01, 4.926798e-01, 5.802978e-01,
3.485442e-01, 7.883130e-01, 2.729308e-01, 8.502518e-01,
4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01,
9.037516e-01, 1.198578e-01, 3.966083e-01, 1.403837e-02,
7.328671e-01, 6.793476e-02, 4.040730e-03, 3.033349e-04,
1.125147e-02, 2.375072e-02, 5.818542e-04, 3.075482e-04,
8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03,
8.791153e-04, 2.177831e-04, 9.693054e-04, 6.610250e-05,
2.900813e-02, 5.735490e-03]
correct_answers = {
'Benjamini-Hochberg' => [6.126681e-01, 8.521710e-01, 1.987205e-01,
1.891595e-01, 3.217789e-01, 9.301450e-01,
4.870370e-01, 9.301450e-01, 6.049731e-01,
6.826753e-01, 6.482629e-01, 7.253722e-01,
5.280973e-01, 8.769926e-01, 4.705703e-01,
9.241867e-01, 6.049731e-01, 7.856107e-01,
4.887526e-01, 1.136717e-01, 4.991891e-01,
8.769926e-01, 9.991834e-01, 3.217789e-01,
9.301450e-01, 2.304958e-01, 5.832475e-01,
3.899547e-02, 8.521710e-01, 1.476843e-01,
1.683638e-02, 2.562902e-03, 3.516084e-02,
6.250189e-02, 3.636589e-03, 2.562902e-03,
2.946883e-02, 6.166064e-03, 3.899547e-02,
2.688991e-03, 4.502862e-04, 1.252228e-05,
7.881555e-02, 3.142613e-02, 4.846527e-03,
2.562902e-03, 4.846527e-03, 1.101708e-03,
7.252032e-02, 2.205958e-02],
'Benjamini-Yekutieli' => [1.000000e+00, 1.000000e+00, 8.940844e-01,
8.510676e-01, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 5.114323e-01, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00,
1.754486e-01, 1.000000e+00, 6.644618e-01,
7.575031e-02, 1.153102e-02, 1.581959e-01,
2.812089e-01, 1.636176e-02, 1.153102e-02,
1.325863e-01, 2.774239e-02, 1.754486e-01,
1.209832e-02, 2.025930e-03, 5.634031e-05,
3.546073e-01, 1.413926e-01, 2.180552e-02,
1.153102e-02, 2.180552e-02, 4.956812e-03,
3.262838e-01, 9.925057e-02],
'Bonferroni' => [1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 7.019185e-01,
1.000000e+00, 1.000000e+00, 2.020365e-01, 1.516674e-02,
5.625735e-01, 1.000000e+00, 2.909271e-02, 1.537741e-02,
4.125636e-01, 6.782670e-02, 6.803480e-01, 1.882294e-02,
9.005725e-04, 1.252228e-05, 1.000000e+00, 4.713920e-01,
4.395577e-02, 1.088915e-02, 4.846527e-02, 3.305125e-03,
1.000000e+00, 2.867745e-01],
'Hochberg' => [9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 4.632662e-01,
9.991834e-01, 9.991834e-01, 1.575885e-01, 1.383967e-02,
3.938014e-01, 7.600230e-01, 2.501973e-02, 1.383967e-02,
3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01,
3.692284e-02, 1.023581e-02, 3.974152e-02, 3.172920e-03,
8.992520e-01, 2.179486e-01],
'Holm' => [1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00,
1.000000e+00, 1.000000e+00, 1.000000e+00, 4.632662e-01,
1.000000e+00, 1.000000e+00, 1.575885e-01, 1.395341e-02,
3.938014e-01, 7.600230e-01, 2.501973e-02, 1.395341e-02,
3.052971e-01, 5.426136e-02, 4.626366e-01, 1.656419e-02,
8.825610e-04, 1.252228e-05, 9.930759e-01, 3.394022e-01,
3.692284e-02, 1.023581e-02, 3.974152e-02, 3.172920e-03,
8.992520e-01, 2.179486e-01],
'Hommel' => [9.991834e-01, 9.991834e-01, 9.991834e-01, 9.987624e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.595180e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 9.991834e-01,
9.991834e-01, 9.991834e-01, 9.991834e-01, 4.351895e-01,
9.991834e-01, 9.766522e-01, 1.414256e-01, 1.304340e-02,
3.530937e-01, 6.887709e-01, 2.385602e-02, 1.322457e-02,
2.722920e-01, 5.426136e-02, 4.218158e-01, 1.581127e-02,
8.825610e-04, 1.252228e-05, 8.743649e-01, 3.016908e-01,
3.516461e-02, 9.582456e-03, 3.877222e-02, 3.172920e-03,
8.122276e-01, 1.950067e-01]
}
# correct_answers.each do |method, answers|
methods = ['Benjamini-Yekutieli', 'Benjamini-Hochberg', 'Hochberg',
'Bonferroni', 'Holm', 'Hommel']
methods.each do |method|
puts method
error = 0.0
arr_q = p_adjust(pvalues, method)
arr_q.each_index do |p|
error += (correct_answers[method][p] - arr_q[p])
end
puts "total error for #{method} = #{error}"
end

View file

@ -0,0 +1,232 @@
use std::iter;
#[rustfmt::skip]
const PVALUES:[f64;50] = [
4.533_744e-01, 7.296_024e-01, 9.936_026e-02, 9.079_658e-02, 1.801_962e-01,
8.752_257e-01, 2.922_222e-01, 9.115_421e-01, 4.355_806e-01, 5.324_867e-01,
4.926_798e-01, 5.802_978e-01, 3.485_442e-01, 7.883_130e-01, 2.729_308e-01,
8.502_518e-01, 4.268_138e-01, 6.442_008e-01, 3.030_266e-01, 5.001_555e-02,
3.194_810e-01, 7.892_933e-01, 9.991_834e-01, 1.745_691e-01, 9.037_516e-01,
1.198_578e-01, 3.966_083e-01, 1.403_837e-02, 7.328_671e-01, 6.793_476e-02,
4.040_730e-03, 3.033_349e-04, 1.125_147e-02, 2.375_072e-02, 5.818_542e-04,
3.075_482e-04, 8.251_272e-03, 1.356_534e-03, 1.360_696e-02, 3.764_588e-04,
1.801_145e-05, 2.504_456e-07, 3.310_253e-02, 9.427_839e-03, 8.791_153e-04,
2.177_831e-04, 9.693_054e-04, 6.610_250e-05, 2.900_813e-02, 5.735_490e-03
];
#[derive(Debug)]
enum CorrectionType {
BenjaminiHochberg,
BenjaminiYekutieli,
Bonferroni,
Hochberg,
Holm,
Hommel,
Sidak,
}
enum SortDirection {
Increasing,
Decreasing,
}
/// orders **input** vector by value and multiplies with **multiplier** vector
/// Finally returns the multiplied values in the original order of **input**
fn ordered_multiply(input: &[f64], multiplier: &[f64], direction: &SortDirection) -> Vec<f64> {
let order_by_value = match direction {
SortDirection::Increasing => {
|a: &(f64, usize), b: &(f64, usize)| b.0.partial_cmp(&a.0).unwrap()
}
SortDirection::Decreasing => {
|a: &(f64, usize), b: &(f64, usize)| a.0.partial_cmp(&b.0).unwrap()
}
};
let cmp_minmax = match direction {
SortDirection::Increasing => |a: f64, b: f64| a.gt(&b),
SortDirection::Decreasing => |a: f64, b: f64| a.lt(&b),
};
// add original order index
let mut input_indexed = input
.iter()
.enumerate()
.map(|(idx, &p_value)| (p_value, idx))
.collect::<Vec<_>>();
// order by value desc/asc
input_indexed.sort_unstable_by(order_by_value);
// do the multiplication in place, clamp it at 1.0,
// keep the original index in place
for i in 0..input_indexed.len() {
input_indexed[i] = (
f64::min(1.0, input_indexed[i].0 * multiplier[i]),
input_indexed[i].1,
);
}
// make vector strictly monotonous increasing/decreasing in place
for i in 1..input_indexed.len() {
if cmp_minmax(input_indexed[i].0, input_indexed[i - 1].0) {
input_indexed[i] = (input_indexed[i - 1].0, input_indexed[i].1);
}
}
// re-sort back to original order
input_indexed.sort_unstable_by(|a: &(f64, usize), b: &(f64, usize)| a.1.cmp(&b.1));
// remove ordering index
let (resorted, _): (Vec<_>, Vec<_>) = input_indexed.iter().cloned().unzip();
resorted
}
#[allow(clippy::cast_precision_loss)]
fn hommel(input: &[f64]) -> Vec<f64> {
// using algorith described:
// http://stat.wharton.upenn.edu/~steele/Courses/956/ResourceDetails/MultipleComparision/Writght92.pdf
// add original order index
let mut input_indexed = input
.iter()
.enumerate()
.map(|(idx, &p_value)| (p_value, idx))
.collect::<Vec<_>>();
// order by value asc
input_indexed
.sort_unstable_by(|a: &(f64, usize), b: &(f64, usize)| a.0.partial_cmp(&b.0).unwrap());
let (p_values, order): (Vec<_>, Vec<_>) = input_indexed.iter().cloned().unzip();
let n = input.len();
// initial minimal n*p/i values
// get the smalles of these values
let min_result = (0..n)
.map(|i| ((p_values[i] * n as f64) / (i + 1) as f64))
.fold(1. / 0. /* -inf */, f64::min);
// // initialize result vector with minimal values
let mut result = iter::repeat(min_result).take(n).collect::<Vec<_>>();
for m in (2..n).rev() {
let cmin: f64;
let m_as_float = m as f64;
let mut a = p_values.clone();
// println!("\nn: {}", m);
{
// split p-values into two group
let (_, second) = p_values.split_at(n - m + 1);
// calculate minumum of m*p/i for this second group
cmin = second
.iter()
.zip(2..=m)
.map(|(p, i)| (m_as_float * p) / i as f64)
.fold(1. / 0. /* inf */, f64::min);
}
// replace p values if p<cmin in the second group
((n - m + 1)..n).for_each(|i| a[i] = a[i].max(cmin));
// replace p values if min(cmin, m*p) > p
(0..=(n - m)).for_each(|i| a[i] = a[i].max(f64::min(cmin, m_as_float * p_values[i])));
// store in the result vector if any adjusted p is higher than the current one
(0..n).for_each(|i| result[i] = result[i].max(a[i]));
}
// re-sort into the original order
let mut result = result
.into_iter()
.zip(order.into_iter())
.map(|(p, idx)| (p, idx))
.collect::<Vec<_>>();
result.sort_unstable_by(|a: &(f64, usize), b: &(f64, usize)| a.1.cmp(&b.1));
let (result, _): (Vec<_>, Vec<_>) = result.iter().cloned().unzip();
result
}
#[allow(clippy::cast_precision_loss)]
fn p_value_correction(p_values: &[f64], ctype: &CorrectionType) -> Vec<f64> {
let p_vec = p_values.to_vec();
if p_values.is_empty() {
return p_vec;
}
let fsize = p_values.len() as f64;
match ctype {
CorrectionType::BenjaminiHochberg => {
let multiplier = (0..p_values.len())
.map(|index| fsize / (fsize - index as f64))
.collect::<Vec<_>>();
ordered_multiply(&p_vec, &multiplier, &SortDirection::Increasing)
}
CorrectionType::BenjaminiYekutieli => {
let q: f64 = (1..=p_values.len()).map(|index| 1. / index as f64).sum();
let multiplier = (0..p_values.len())
.map(|index| q * fsize / (fsize - index as f64))
.collect::<Vec<_>>();
ordered_multiply(&p_vec, &multiplier, &SortDirection::Increasing)
}
CorrectionType::Bonferroni => p_vec
.iter()
.map(|p| f64::min(p * fsize, 1.0))
.collect::<Vec<_>>(),
CorrectionType::Hochberg => {
let multiplier = (0..p_values.len())
.map(|index| 1. + index as f64)
.collect::<Vec<_>>();
ordered_multiply(&p_vec, &multiplier, &SortDirection::Increasing)
}
CorrectionType::Holm => {
let multiplier = (0..p_values.len())
.map(|index| fsize - index as f64)
.collect::<Vec<_>>();
ordered_multiply(&p_vec, &multiplier, &SortDirection::Decreasing)
}
CorrectionType::Sidak => p_vec
.iter()
.map(|x| 1. - (1. - x).powf(fsize))
.collect::<Vec<_>>(),
CorrectionType::Hommel => hommel(&p_vec),
}
}
// prints array into a nice table, max 5 floats/row
fn array_to_string(a: &[f64]) -> String {
a.chunks(5)
.enumerate()
.map(|(index, e)| {
format!(
"[{:>2}]: {}",
index * 5,
e.iter()
.map(|x| format!("{:>1.10}", x))
.collect::<Vec<_>>()
.join(", ")
)
})
.collect::<Vec<_>>()
.join("\n")
}
fn main() {
let ctypes = [
CorrectionType::BenjaminiHochberg,
CorrectionType::BenjaminiYekutieli,
CorrectionType::Bonferroni,
CorrectionType::Hochberg,
CorrectionType::Holm,
CorrectionType::Sidak,
CorrectionType::Hommel,
];
for ctype in &ctypes {
println!("\n{:?}:", ctype);
println!("{}", array_to_string(&p_value_correction(&PVALUES, ctype)));
}
}

View file

@ -0,0 +1,18 @@
data pvalues;
input raw_p @@;
cards;
4.533744e-01 7.296024e-01 9.936026e-02 9.079658e-02 1.801962e-01
8.752257e-01 2.922222e-01 9.115421e-01 4.355806e-01 5.324867e-01
4.926798e-01 5.802978e-01 3.485442e-01 7.883130e-01 2.729308e-01
8.502518e-01 4.268138e-01 6.442008e-01 3.030266e-01 5.001555e-02
3.194810e-01 7.892933e-01 9.991834e-01 1.745691e-01 9.037516e-01
1.198578e-01 3.966083e-01 1.403837e-02 7.328671e-01 6.793476e-02
4.040730e-03 3.033349e-04 1.125147e-02 2.375072e-02 5.818542e-04
3.075482e-04 8.251272e-03 1.356534e-03 1.360696e-02 3.764588e-04
1.801145e-05 2.504456e-07 3.310253e-02 9.427839e-03 8.791153e-04
2.177831e-04 9.693054e-04 6.610250e-05 2.900813e-02 5.735490e-03
;
run;
proc multtest pdata=pvalues bon sid hom hoc holm;
run;

View file

@ -0,0 +1 @@
ssc install qqvalue

View file

@ -0,0 +1,23 @@
clear
#delimit ;
input p;
4.533744e-01;7.296024e-01;9.936026e-02;9.079658e-02;1.801962e-01;
8.752257e-01;2.922222e-01;9.115421e-01;4.355806e-01;5.324867e-01;
4.926798e-01;5.802978e-01;3.485442e-01;7.883130e-01;2.729308e-01;
8.502518e-01;4.268138e-01;6.442008e-01;3.030266e-01;5.001555e-02;
3.194810e-01;7.892933e-01;9.991834e-01;1.745691e-01;9.037516e-01;
1.198578e-01;3.966083e-01;1.403837e-02;7.328671e-01;6.793476e-02;
4.040730e-03;3.033349e-04;1.125147e-02;2.375072e-02;5.818542e-04;
3.075482e-04;8.251272e-03;1.356534e-03;1.360696e-02;3.764588e-04;
1.801145e-05;2.504456e-07;3.310253e-02;9.427839e-03;8.791153e-04;
2.177831e-04;9.693054e-04;6.610250e-05;2.900813e-02;5.735490e-03;
end;
#delimit cr
loc meth bonferroni sidak holm holland hochberg simes yekutieli
foreach m in `meth' {
qqvalue p, method(`m') qvalue(`m')
}
list

View file

@ -0,0 +1,155 @@
import "/dynamic" for Enum
import "/fmt" for Fmt
import "/seq" for Lst
import "/math" for Nums
import "/sort" for Sort
var Direction = Enum.create("Direction", ["UP", "DOWN"])
// test also for 'Unknown' correction type
var types = [
"Benjamini-Hochberg", "Benjamini-Yekutieli", "Bonferroni", "Hochberg",
"Holm", "Hommel", "Šidák", "Unknown"
]
var pFormat = Fn.new { |p, cols|
var i = -cols
var fmt = "$1.10f"
return Lst.chunks(p, cols).map { |chunk|
i = i + cols
return Fmt.swrite("[$2d $s", i, chunk.map { |v| Fmt.swrite(fmt, v) }.join(" "))
}.join("\n")
}
var check = Fn.new { |p|
if (p.count == 0 || Nums.min(p) < 0 || Nums.max(p) > 1) {
Fiber.abort("p-values must be in range 0 to 1")
}
return p
}
var ratchet = Fn.new { |p, dir|
var pp = p.toList
var m = pp[0]
if (dir == Direction.UP) {
for (i in 1...pp.count) {
if (pp[i] > m) pp[i] = m
m = pp[i]
}
} else {
for (i in 1...pp.count) {
if (pp[i] < m) pp[i] = m
m = pp[i]
}
}
return pp.map { |v| (v < 1) ? v : 1 }.toList
}
var schwartzian = Fn.new { |p, mult, dir|
var size = p.count
var pwi = List.filled(size, null)
for (i in 0...size) pwi[i] = [i, p[i]]
var cmp = (dir == Direction.UP) ? Fn.new { |a, b| (b[1] - a[1]).sign } :
Fn.new { |a, b| (a[1] - b[1]).sign }
var order = Sort.merge(pwi, cmp).map { |e| e[0] }.toList
var pa = List.filled(size, 0)
for (i in 0...size) pa[i] = mult[i] * p[order[i]]
pa = ratchet.call(pa, dir)
var owi = List.filled(order.count, null)
for (i in 0...order.count) owi[i] = [i, order[i]]
cmp = Fn.new { |a, b| (a[1] - b[1]).sign }
var order2 = Sort.merge(owi, cmp).map { |e| e[0] }.toList
var res = List.filled(size, 0)
for (i in 0...size) res[i] = pa[order2[i]]
return res
}
var adjust = Fn.new { |p, type|
var size = p.count
if (size == 0) Fiber.abort("List cannot be empty.")
if (type == "Benjamini-Hochberg") {
var mult = List.filled(size, 0)
for (i in 0...size) mult[i] = size / (size - i)
return schwartzian.call(p, mult, Direction.UP)
} else if (type == "Benjamini-Yekutieli") {
var q = (1..size).reduce { |acc, i| acc + 1/i }
var mult = List.filled(size, 0)
for (i in 0...size) mult[i] = q * size / (size - i)
return schwartzian.call(p, mult, Direction.UP)
} else if (type == "Bonferroni") {
return p.map { |v| (v * size).min(1) }.toList
} else if (type == "Hochberg") {
var mult = List.filled(size, 0)
for (i in 0...size) mult[i] = i + 1
return schwartzian.call(p, mult, Direction.UP)
} else if (type == "Holm") {
var mult = List.filled(size, 0)
for (i in 0...size) mult[i] = size - i
return schwartzian.call(p, mult, Direction.DOWN)
} else if (type == "Hommel") {
var pwi = List.filled(size, null)
for (i in 0...size) pwi[i] = [i, p[i]]
var cmp = Fn.new { |a, b| (a[1] - b[1]).sign }
var order = Sort.merge(pwi, cmp).map { |e| e[0] }.toList
var s = List.filled(size, 0)
for (i in 0...size) s[i] = p[order[i]]
var m = List.filled(size, 0)
for (i in 0...size) m[i] = s[i] * size / (i + 1)
var min = Nums.min(m)
var q = List.filled(size, min)
var pa = List.filled(size, min)
for (j in size-1..2) {
var lower = List.filled(size - j + 1, 0) // lower indices
for (i in 0...lower.count) lower[i] = i
var upper = List.filled(j - 1, 0) // upper indices
for (i in 0...upper.count) upper[i] = size - j + 1 + i
var qmin = j * s[upper[0]] / 2
for (i in 1...upper.count) {
var temp = s[upper[i]] * j / (2 + i)
if (temp < qmin) qmin = temp
}
for (i in 0...lower.count) {
q[lower[i]] = qmin.min(s[lower[i]] * j)
}
for (i in 0...upper.count) q[upper[i]] = q[size - j]
for (i in 0...size) if (pa[i] < q[i]) pa[i] = q[i]
}
var owi = List.filled(order.count, null)
for (i in 0...order.count) owi[i] = [i, order[i]]
var order2 = Sort.merge(owi, cmp).map { |e| e[0] }.toList
var res = List.filled(size, 0)
for (i in 0...size) res[i] = pa[order2[i]]
return res
} else if (type == "Šidák") {
return p.map { |v| 1 - (1 - v).pow(size) }.toList
} else {
System.print("\nSorry, do not know how to do '%(type)' correction.\n" +
"Perhaps you want one of these?:\n" +
types[0...-1].map { |t| " %(t)" }.join("\n")
)
Fiber.suspend()
}
}
var adjusted = Fn.new { |p, type| "\n%(type)\n%(pFormat.call(adjust.call(check.call(p), type), 5))" }
var pValues = [
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03
]
types.each { |type| System.print(adjusted.call(pValues, type)) }

View file

@ -0,0 +1,65 @@
fcn bh(pvalues){ // Benjamini-Hochberg
psz,pszf := pvalues.len(), psz.toFloat();
n_i := psz.pump(List,'wrap(n){ pszf/(psz - n) }); # N/(N-0),N/(N-1),..
o,ro := order(pvalues,True),order(o,False); # sort pvalues, sort indices
in := psz.pump(List,'wrap(n){ n_i[n]*pvalues[o[n]] });
pmin := cummin(in).apply((1.0).min); # (min(1,c[0]),min(1,c[1]),...)
ro.apply(pmin.get); # (pmin[ro[0]],pmin[ro[1]],...)
}
fcn by(pvalues){ // Benjamini & Yekutieli
psz,pszf := pvalues.len(), psz.toFloat();
o,ro := order(pvalues,True),order(o,False); # sort pvalues, sort indices
n_i := psz.pump(List,'wrap(n){ pszf/(psz - n) }); # N/(N-0),N/(N-1),..
q := [1..psz].reduce(fcn(q,n){ q+=1.0/n },0.0);
in := psz.pump(List,'wrap(n){ q * n_i[n] * pvalues[o[n]] });
cummin(in).apply((1.0).min) : ro.apply(_.get);
}
fcn hochberg(pvalues){
psz,pszf := pvalues.len(), psz.toFloat();
o,ro := order(pvalues,True),order(o,False); # sort pvalues, sort indices
n_i := psz.pump(List,'wrap(n){ pszf/(psz - n) }); # N/(N-0),N/(N-1),..
in := psz.pump(List,'wrap(n){ pvalues[o[n]]*(n + 1) });
cummin(in).apply((1.0).min) : ro.apply(_.get);
}
fcn cummin(pvalues){ // R's cumulative minima --> list of mins
out,m := List.createLong(pvalues.len()), pvalues[0];
foreach pv in (pvalues){ out.append(m=m.min(pv)) }
out
}
fcn order(list,downUp){ // True==increasing, --> List(int) sorted indices
f:=(downUp) and fcn(a,b){ a[1]>b[1] } or fcn(a,b){ a[1]<b[1] };
[0..].zip(list).pump(List()).sort(f).pump(List,T("get",0))
}
fcn bonferroni(pvalues){ // -->List
sz,r := pvalues.len(),List();
foreach pv in (pvalues){
b:=pv*sz;
if(b>=1.0) r.append(1.0);
else if(0.0<=b<1.0) r.append(b);
else throw(Exception.ValueError(
"%g is outside of the interval I planned.".fmt(b)));
}
r
}
fcn hommel(pvalues){
psz,indices := pvalues.len(), [1..psz].walk(); // 1,2,3,4...
o,ro := order(pvalues,False),order(o,False); # sort pvalues, sort indices
p := o.apply('wrap(n){ pvalues[n] }).copy(); // pvalues[*o]
npi := [1..].zip(p).apply('wrap([(n,p)]){ p*psz/n });
min := (0.0).min(npi); // min value in npi
pa,q := List.createLong(psz,min), pa.copy(); #(min,min,,,)
foreach j in ([psz - 1..2,-1]){
ij:=[0..psz - j].walk();
i2:=(j - 1).pump(List,'+(psz - j + 1));
q1:=(0.0).min((j-1).pump(List,'wrap(n){ p[i2[n]]*j/(2 + n) }));
foreach i in (psz - j + 1){ q[ij[i]] = q1.min(p[ij[i]]*j) }
foreach i in (j - 1){ q[i2[i]] = q[psz - j] }
foreach i in (psz){ pa[i] = pa[i].max(q[i]) }
}
psz.pump(List,'wrap(n){ pa[ro[n]] }); // Hommel q-values
}

View file

@ -0,0 +1,26 @@
pvalues:=T(
4.533744e-01, 7.296024e-01, 9.936026e-02, 9.079658e-02, 1.801962e-01,
8.752257e-01, 2.922222e-01, 9.115421e-01, 4.355806e-01, 5.324867e-01,
4.926798e-01, 5.802978e-01, 3.485442e-01, 7.883130e-01, 2.729308e-01,
8.502518e-01, 4.268138e-01, 6.442008e-01, 3.030266e-01, 5.001555e-02,
3.194810e-01, 7.892933e-01, 9.991834e-01, 1.745691e-01, 9.037516e-01,
1.198578e-01, 3.966083e-01, 1.403837e-02, 7.328671e-01, 6.793476e-02,
4.040730e-03, 3.033349e-04, 1.125147e-02, 2.375072e-02, 5.818542e-04,
3.075482e-04, 8.251272e-03, 1.356534e-03, 1.360696e-02, 3.764588e-04,
1.801145e-05, 2.504456e-07, 3.310253e-02, 9.427839e-03, 8.791153e-04,
2.177831e-04, 9.693054e-04, 6.610250e-05, 2.900813e-02, 5.735490e-03);
bh(pvalues) : format(_,"\nBenjamini-Hochberg");
by(pvalues) : format(_,"\nBenjamini & Yekutieli");
bonferroni(pvalues) : format(_,"\nBonferroni");
hochberg(pvalues) : format(_,"\nHochberg");
hommel(pvalues) : format(_,"\nHommel");
fcn format(list,title){
print(title,":");
foreach n in ([1..list.len(),5]){
print("\n[%2d]:".fmt(n));
foreach x in (list[n-1,5]){ print(" %.6e".fmt(x)) }
}
println();
}