public double CalcPiZeroLambda() { // As in Storey and Tibshirani 2003 calculate Pi-zero across a range of // p value cut-offs. var lambdas = PiZeroLambdas.ToArray(); var piZeros = PiZeros(lambdas); double minPi0 = piZeros.Min(); // Because the spline fitting described in Storey and Tibshirani 2003 // is non-trivial to implement in C#, the method in use in Percolator // is used instead. // Find the lambda level closest to the minimum with enough precision // by testing sets of p values drawn at random from the current set. double[] arrayMse = new double[lambdas.Length]; int numDraw = Math.Min(Length, RANDOM_DRAWS_MAX); var rand = new Random(0); // Use a fixed random seed value for reproducible results for (int r = 0; r < RANDOM_CYCLE_COUNT; r++) { // Create an array of p-values randomly drawn from the current set var statBoot = new Statistics(RandomDraw(rand).Take(numDraw)); piZeros = statBoot.PiZeros(lambdas); for (int i = 0; i < lambdas.Length; ++i) { double pi0Boot = piZeros[i]; // Estimated mean-squared error. arrayMse[i] += (pi0Boot - minPi0) * (pi0Boot - minPi0); } } // Use the original estimate for the lambda that produced // the minimum mean-squared error for the random draw iterations int iMin = arrayMse.IndexOf(v => v == arrayMse.Min()); return lambdas[iMin]; }