public double getCachedValue(ContingencyTable ct) { int[] aKey = new int[] { ct.getA(), ct.getB(), ct.getC(), ct.getD() }; if (m_slContingencyTables.ContainsKey(aKey)) { return(m_slContingencyTables[aKey]); } return(double.NaN); }
/** * Computes the hypergeometric probablity using the following factorization: * (a+b)!(a+c)!(b+d)!(c+d)! (a+b)! (a+c)! (c+d)! (b+d)! * ------------------------ = ------- * ------- * -------- * -------- * a!b!c!d!n! a!b! c! d! n! * The assumption is that (a+b) is the smallest marginal. * A better implementation would check for the smallest marginal and factor according to it, but the current implementation seems fast enough. * */ public static double pr(ContingencyTable ct) { double pt = 1; double iFactorial = 0; int a = ct.getA(), b = ct.getB(), c = ct.getC(), d = ct.getD(); double iDenominator = a + b + c + d; double iMinDenominator = b + d; for (iFactorial = a + 1; iFactorial <= a + b; iFactorial++) // (a+b)!/a!b! { pt *= iFactorial / (iFactorial - a); while ((pt > 1) && (iDenominator > iMinDenominator)) { pt /= iDenominator; iDenominator--; } } for (iFactorial = c + 1; iFactorial <= a + c; iFactorial++) // (a+c)!/c! { pt *= iFactorial; while ((pt > 1) && (iDenominator > iMinDenominator)) { pt /= iDenominator; iDenominator--; } } for (iFactorial = d + 1; iFactorial <= c + d; iFactorial++) // (c+d)!/d! { pt *= iFactorial; while ((pt > 1) && (iDenominator > iMinDenominator)) { pt /= iDenominator; iDenominator--; } } if (pt == 0.0) //underflow { return(double.Epsilon); } while ((iDenominator > iMinDenominator) && (pt > 0.0)) { pt /= iDenominator; if (pt == 0.0) //underflow { return(double.Epsilon); } iDenominator--; } if (pt > 1.0) //numerical error { pt = 1.0; } return(pt); }
public void setCachedValue(ContingencyTable ct, double dValue) { int[] aKey = new int[] { ct.getA(), ct.getB(), ct.getC(), ct.getD() }; if (!m_slContingencyTables.ContainsKey(aKey)) { m_slContingencyTables.Add(aKey, dValue); } else { m_slContingencyTables[aKey] = dValue; } }
/** * Computes the Fisher 2 sided p-value. * We iterate over all the premutations and sum the ones that have a lower probability (more extreme). * We compute from scratch only a single hypergeometric probability - the probability of the "real" table. * Then we iterate by incrementing the table and the probability (right side) and by decrementing the table and the probability (left side). * The algorithm has the complexity of O(n), but usually runs much faster. * Adding another possible optimization - when the p-value exceeds a cutoff - return 1. This is useful when we only need to know whether one value is larger than the other. * When the values are too small to be represented by a double (less than 1-E302) the computation returns an upper bound on the real value. * */ private double computeFisher2TailPermutationTest(double dObservedTableProbability, double dCutoff) { double p0 = dObservedTableProbability; double p0Epsilon = p0 * 0.00001; double p = p0, pt = 0, pAbove = 0.0, pLeft = p0, pRight = 0.0; ContingencyTable ctIterator = null; int cPermutations = 0, cRemiaingPermutations = getMaxPossibleA() - getMinPossibleA(); m_dMinimalPValue = p0; if (p0 == double.Epsilon) { return(p0 * cRemiaingPermutations); //an upper bound estimation } //Iterate to the right side - increasing values of a if (g_ttTestType == TestType.Right || g_ttTestType == TestType.TwoSided) { ctIterator = next(); pt = incrementalHypergeometricProbability(p0); while (ctIterator != null) { if (pt < m_dMinimalPValue) { m_dMinimalPValue = pt; } cPermutations++; if (p0 + p0Epsilon >= pt) { p = p + pt; pLeft += pt; if (p > dCutoff) { return(1.0); } } else { pAbove += pt; } pt = ctIterator.incrementalHypergeometricProbability(pt); ctIterator = ctIterator.next(); if ((ctIterator != null) && (pt <= p0Epsilon)) { pt *= (getMaxPossibleA() - ctIterator.getA() + 1); p += pt; pLeft += pt; ctIterator = null; } } } //Iterate to the left side - decreasing values of a if (g_ttTestType == TestType.Left || g_ttTestType == TestType.TwoSided) { ctIterator = previous(); pt = decrementalHypergeometricProbability(p0); double dBackward = pt; while (ctIterator != null) { if (pt < m_dMinimalPValue) { m_dMinimalPValue = pt; } cPermutations++; if (p0 + p0Epsilon >= pt) { p = p + pt; pRight += pt; if (p > dCutoff) { return(1.0); } } else { pAbove += pt; } double dBefore = pt; pt = ctIterator.decrementalHypergeometricProbability(pt); ctIterator = ctIterator.previous(); if ((ctIterator != null) && (pt <= p0Epsilon)) { pt *= (ctIterator.getA() - getMinPossibleA()); p += pt; pRight += pt; ctIterator = null; } } } m_cComputedFisherScores++; return(p); }
public double[] computeAllFisherStatistics(double[] adResults, ref bool bApproximated) { double p0 = getHypergeometricProbability();// probability of seeing the actual data double p0Epsilon = p0 * 0.00001; double p = p0, pt = 0, ptMax = 0.0, pLeft = p0, pRight = p0; ContingencyTable ctMaxTable = getMaxValueTable(), ctIterator = ctMaxTable; int iMaxA = getMaxPossibleA(), iMinA = getMinPossibleA(); int cPermutations = 0, cRemiaingPermutations = iMaxA - iMinA; int iCurrentA = 0; double[] adMapping = new double[iMaxA + 1]; adResults[0] = p0; ptMax = ctIterator.getHypergeometricProbability(); pt = ptMax; while (ctIterator != null) { cPermutations++; iCurrentA = ctIterator.getA(); adMapping[iCurrentA] = pt; if (iCurrentA > m_iA) { pRight += pt; } if (iCurrentA < m_iA) { pLeft += pt; } if (p0 + p0Epsilon >= pt && iCurrentA != m_iA) { p = p + pt; } pt = ctIterator.incrementalHypergeometricProbability(pt); ctIterator = ctIterator.next(); if ((ctIterator != null) && (pt == double.Epsilon)) { pt *= (iMaxA - ctIterator.getA() + 1); p += pt; pRight += pt; bApproximated = true; for (iCurrentA = ctIterator.getA(); iCurrentA <= iMaxA; iCurrentA++) { adMapping[iCurrentA] = double.Epsilon; } ctIterator = null; } } //Iterate to the left side - decreasing values of a ctIterator = ctMaxTable.previous(); pt = ctMaxTable.decrementalHypergeometricProbability(ptMax); while (ctIterator != null) { cPermutations++; iCurrentA = ctIterator.getA(); adMapping[iCurrentA] = pt; if (iCurrentA > m_iA) { pRight += pt; } if (iCurrentA < m_iA) { pLeft += pt; } if (p0 + p0Epsilon >= pt && iCurrentA != m_iA) { p = p + pt; } pt = ctIterator.decrementalHypergeometricProbability(pt); ctIterator = ctIterator.previous(); if ((ctIterator != null) && (pt == double.Epsilon)) { pt *= (ctIterator.getA() - getMinPossibleA()); p += pt; pLeft += pt; bApproximated = true; for (iCurrentA = ctIterator.getA(); iCurrentA >= iMinA; iCurrentA--) { adMapping[iCurrentA] = double.Epsilon; } ctIterator = null; } } for (iCurrentA = iMinA - 1; iCurrentA >= 0; iCurrentA--) { adMapping[iCurrentA] = 0.0; } adResults[1] = pLeft; adResults[2] = pRight; adResults[3] = p; return(adMapping); }