我需要对矩阵n x m进行Fisher精确检验。我一直在寻找几个小时,我只找到了一个示例代码,但它是用Fortran编写的。我一直在Wolfram工作,我接近完成,但我错过了最后一点。
/**
* Performs Fisher's Exact Test on a matrix m x n
* @param matrix Any matrix m x n.
* @return The Fisher's Exact value of the matrix
* @throws IllegalArgumentException If the rows are not of equal length
* @author Ryan Amos
*/
public static double getFisherExact(int[][] matrix){
System.out.println("Working with matrix: ");
printMatrix(matrix);
for (int[] array : matrix) {
if(array.length != matrix[0].length)
throw new IllegalArgumentException();
}
boolean chiSq = matrix.length != 2 || matrix[0].length != 2;
int[] rows = new int[matrix.length];
int[] columns = new int[matrix[0].length];
int n;
//compute R and C values
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
rows[i] += matrix[i][j];
columns[j] += matrix[i][j];
}
System.out.println("rows[" + i + "] = " + rows[i]);
}
for (int i = 0; i < columns.length; i++) {
System.out.println("columns[" + i + "] = " + columns[i]);
}
//compute n
n = 0;
for (int i = 0; i < columns.length; i++) {
n += columns[i];
}
int[][][] perms = findAllPermutations(rows, columns);
double sum = 0;
//int count = 0;
double cutoff = chiSq ? getChiSquaredValue(matrix, rows, columns, n) : getConditionalProbability(matrix, rows, columns, n);
System.out.println("P cutoff = " + cutoff + "\n");
for (int[][] is : perms) {
System.out.println("Matrix: ");
printMatrix(is);
double val = chiSq ? getChiSquaredValue(is, rows, columns, n) : getConditionalProbability(is, rows, columns, n);
System.out.print("Value: " + val);
if(val <= cutoff){
//count++;
System.out.print(" is below " + cutoff);
// sum += (chiSq) ? getConditionalProbability(is, rows, columns, n) : val;
// sum += val;
double p = getConditionalProbability(is, rows, columns, n);
System.out.print("\np = " + p + "\nsum = " + sum + " + p = ");
sum += p;
System.out.print(sum);
} else {
System.out.println(" is above " + cutoff + "\np = " + getConditionalProbability(is, rows, columns, n));
}
System.out.print("\n\n");
}
return sum;
//return count / (double)perms.length;
}
所有其他方法都经过测试和调试。问题是我不确定从哪里找到所有可能的矩阵(所有矩阵具有相同的行和列总和)。我不确定如何将这些矩阵转换为p值。我读了一些关于卡方的东西,所以我找到了一个卡方算法。
所以我的问题是: 从我所拥有的(矩阵的所有排列),我如何计算p值? 我的所有尝试都在最后一个for循环中,或者在最后一个for循环中注释掉。
答案 0 :(得分:1)
编辑:
看看wolfram,似乎可以通过以下方式解决n x m尺寸问题:
public static BigDecimal getHypergeometricDistribution(//
int a[][], int scale, int roundingMode//
) throws OutOfMemoryError, NullPointerException {
ArrayList<Integer> R = new ArrayList<Integer>();
ArrayList<Integer> C = new ArrayList<Integer>();
ArrayList<Integer> E = new ArrayList<Integer>();
int n = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
if (a[i][j] < 0)
return null;
n += a[i][j];
add(C, j, a[i][j]);
add(R, i, a[i][j]);
E.add(a[i][j]);
}
}
BigDecimal term1 = //
new BigDecimal(multiplyFactorials(C).multiply(multiplyFactorials(R)));
BigDecimal term2 = //
new BigDecimal(getFactorial(n).multiply(multiplyFactorials(E)));
return term1.divide(term2, scale, roundingMode);
}
对于getBinomialCoefficient,getFactorial和评论,请查看我的gist。
因子很快增长,例如:
Wolfram示例案例:
int[][] a = { { 5, 0 }, { 1, 4 } };
System.out.println(hdMM.getHypergeometricDistribution(a, 60, 6));
会导致:
0.023809523809523809523809523809523809523809523809523809523810
编辑2:
我的方法很快,但不是内存效率,如果输入矩阵元素的总和超过10000,这可能是个问题。原因是因子的记忆。
Mathematica中几乎等效的功能,没有这个问题:
FeT1::usage = "Fisher's exact Test, 1 tailed. For more information:
http://mathworld.wolfram.com/FishersExactTest.html";
FeT1[a_List, nr_Integer: 6] := Module[{},
SumRow[array_] := Total[Transpose[array]];
SumTotal[array_] := Total[Total[array]];
SumColumn[array_] := Total[array];
TF[list_] := Times @@ (list!);
N[(TF[SumColumn[a]]*TF[SumRow[a]])/(SumTotal[a]!* TF[Flatten[a]]), nr]
];
和示例用法:
a = {{5, 0}, {1, 4}};
FeT1[a, 59]
会屈服于
0.023809523809523809523809523809523809523809523809523809523810
Mathematica还提供了Fisher's Exact Test实施的统计软件包。恕我直言用Java写这个可以快20%,但需要的努力大约是200%,开发时间是400%。
答案 1 :(得分:1)
这是概率方程(采用LaTeX格式):
给定特定行和列总和的实际矩阵的条件概率,由
给出[![\begin{equation}
\begin{split}
P &=\prod_{i=1}^r \prod_{j=1}^c \frac{n_{i.}!n_{.j}!}{n_{..}!n_{ij}}\\
&=\frac{(n_{1.}!n_{2.}! \cdots n_{r.}!)(n_{.1}!n_{.2}! \cdots n_{.c}!)}{n_{..}!\prod_i \prod_j n_{ij}!}
\end{split}
\end{equation}]
是超几何概率函数的多元推广。
如果您使用100,000次迭代,并且具有较小的表,例如,最多5x5,那么您将非常接近真正精确测试的收敛。
答案 2 :(得分:0)
我找到了问题的答案。今天早上与统计学家交谈后,他让我总结了所有的价值观,看看是什么来的。我发现值的总和(如预期的)高于1.但是,我还发现我可以使用和来将p值缩放到0
小于或等于X ^ 2 p值的矩阵的条件概率值之和
DIVIDED BY
所有矩阵的所有条件概率值的总和
我用R fisher精确测试检查了我的答案