当 Wilcoxon 测试 returns 一些 0 p 值时该怎么办?
What to do when Wilcoxon test returns some 0 p-values?
我在一个大列表中使用 R 执行 Wilcoxon 测试(包含 86 个数据帧,行数和值数可变)。我不明白为什么在 p 值 < 10^-307 之后它 returns 一些 p 值 = 0 然后它 returns 具有“正常”值。
这种情况发生在具有非常多行数(大约 4000 或更多)的数据帧中,但不会出现在具有大约 1000 行的数据帧中。
我的脚本是错误的还是有可能得到 0 个值?如果是这样,是否有特定的方式来解释它们?
这里我报告我的脚本:
for (i in 1 : length(List)) {
for(j in 2 : (nrow(List[[i]]) - 1)){
divider <- (List[[i]][j,2])
ValueInfe <- List[[i]][List[[i]][,2] < divider ,]
ValueSupUgu <- List[[i]][List[[i]][,2] >= divider ,]
if(j == 2){Num_ValoreInfe <- as.numeric(ValoreInfe[2])}
if(j!= 2){Num_ValoreInfe <- as.numeric(ValoreInfe[,2])}
Num_ValoreSupUgu <- as.numeric(ValoreSupUgu[,2])
b <- wilcox.test(Num_ValoreInfe, Num_ValoreSupUgu)
List2.0[[i]][j,3] <- b$p.value
}
}
这是我的结果示例:
0.000000e+00
8.343024e-02
1.435822e-02
2.716505e-03
5.370877e-04
1.089895e-04
2.250558e-05
4.706192e-06
9.936437e-07
2.114061e-07
4.526195e-08
9.741929e-09
2.106339e-09
4.572291e-10
9.960156e-11
9.960156e-11
[...]
0
0
0
0
0
[...]
2.114061e-07
9.936437e-07
4.706192e-06
2.250558e-05
1.089895e-04
5.370877e-04
2.716505e-03
1.435822e-02
0.000000e+00
通常,R 可以区分零的最小数字约为 1e-308(即 10^(-308)) - 具体来说,.Machine$double.xmin
=2.225074e-308。更准确地说,R 可以处理 稍微 较小的值:?Machine
说:
Note that on most platforms smaller positive values than
‘.Machine$double.xmin’ can occur. On a typical R platform the
smallest positive double is about ‘5e-324’.
如果你想处理比这更小的数字,你必须做一些聪明的事情,比如记录它们的对数(log(.Machine$double.xmin)
是 -708,你可以很容易地记录 这样 小得多的数字)。 R 中的一些 p 值计算允许您检索 log-p 值而不是 p 值,但 Wilcoxon 检验没有这样的功能。
虽然如果您非常需要这种能力,也许可以从头开始构建这种能力,但研究人员通常只会将此类 p 值视为“极小”;如果需要,您可以说“<1e-308” .我见过的唯一一个人们担心如此小的 p 值的精确值的研究领域是生物信息学,其中 p 值本身被视为度量标准,而不是统计清晰度的定性指标差异。
这是一个小示例,它测试样本量逐渐增大的非重叠集的 p 值,显示 p 值减小然后下溢到零(请参见位于下方 y 轴上的点图的右边缘):
w <- function(n=20) {
wilcox.test(1:n,1e6+1:n)$p.value
}
nvec <- seq(20,1000,by=10)
pvec <- sapply(nvec,w)
破解 log-p 值
深入研究 stats:::wilcox.test.default
中的代码,我们可以找到根据测试统计和分组样本大小计算 p 值的位置,并使用 log.p=TRUE
重新计算它们.下面的代码跳过了一些细节,例如考虑关系和允许不同的备选假设(即假设是双侧测试)。
这为您提供了 p 值的 自然 对数;您可以通过乘以 log10(exp(1))
...
转换回 log10
wilcox_log_p <- function(x,y,exact=FALSE,correct=TRUE,...) {
## assume two-sided
w <- wilcox.test(x,y,...)
n.x <- length(x)
n.y <- length(y)
STATISTIC <- w$statistic
if (exact) {
if (STATISTIC > (n.x * n.y/2)) {
return(pwilcox(STATISTIC - 1, n.x, n.y,
lower.tail = FALSE, log.p=TRUE))
}
return(pwilcox(STATISTIC, n.x, n.y, log.p=TRUE))
} else {
NTIES <- 0 ## assume no ties!
z <- STATISTIC - n.x * n.y/2
SIGMA <- sqrt((n.x * n.y/12) * ((n.x + n.y + 1) -
sum(NTIES^3 - NTIES)/((n.x + n.y) * (n.x + n.y -
1))))
if (correct) {
CORRECTION <- sign(z) * 0.5
}
z <- (z - CORRECTION)/SIGMA
PVAL <- log(2) + min(pnorm(z, log.p=TRUE),
pnorm(z, lower.tail = FALSE, log.p=TRUE))
return(PVAL)
}
}
w <- function(n=20) {
wilcox.test(1:n,1e6+1:n, exact=FALSE)$p.value
}
w2 <- function(n=20) {
wilcox_log_p(1:n,1e6+1:n)
}
nvec <- seq(20,1100,by=10)
pvec <- sapply(nvec,w)
pvec2 <- sapply(nvec,w2)
dd <- data.frame(n=rep(nvec,2),p=c(log(pvec),pvec2),
method=rep(c("default","log_p"),each=length(nvec)))
library(ggplot2); theme_set(theme_bw())
ggplot(dd, aes(n,p,colour=method)) + geom_point() + geom_line()
scale_x_log10()
我在一个大列表中使用 R 执行 Wilcoxon 测试(包含 86 个数据帧,行数和值数可变)。我不明白为什么在 p 值 < 10^-307 之后它 returns 一些 p 值 = 0 然后它 returns 具有“正常”值。 这种情况发生在具有非常多行数(大约 4000 或更多)的数据帧中,但不会出现在具有大约 1000 行的数据帧中。 我的脚本是错误的还是有可能得到 0 个值?如果是这样,是否有特定的方式来解释它们?
这里我报告我的脚本:
for (i in 1 : length(List)) {
for(j in 2 : (nrow(List[[i]]) - 1)){
divider <- (List[[i]][j,2])
ValueInfe <- List[[i]][List[[i]][,2] < divider ,]
ValueSupUgu <- List[[i]][List[[i]][,2] >= divider ,]
if(j == 2){Num_ValoreInfe <- as.numeric(ValoreInfe[2])}
if(j!= 2){Num_ValoreInfe <- as.numeric(ValoreInfe[,2])}
Num_ValoreSupUgu <- as.numeric(ValoreSupUgu[,2])
b <- wilcox.test(Num_ValoreInfe, Num_ValoreSupUgu)
List2.0[[i]][j,3] <- b$p.value
}
}
这是我的结果示例:
0.000000e+00
8.343024e-02
1.435822e-02
2.716505e-03
5.370877e-04
1.089895e-04
2.250558e-05
4.706192e-06
9.936437e-07
2.114061e-07
4.526195e-08
9.741929e-09
2.106339e-09
4.572291e-10
9.960156e-11
9.960156e-11
[...]
0
0
0
0
0
[...]
2.114061e-07
9.936437e-07
4.706192e-06
2.250558e-05
1.089895e-04
5.370877e-04
2.716505e-03
1.435822e-02
0.000000e+00
通常,R 可以区分零的最小数字约为 1e-308(即 10^(-308)) - 具体来说,.Machine$double.xmin
=2.225074e-308。更准确地说,R 可以处理 稍微 较小的值:?Machine
说:
Note that on most platforms smaller positive values than ‘.Machine$double.xmin’ can occur. On a typical R platform the smallest positive double is about ‘5e-324’.
如果你想处理比这更小的数字,你必须做一些聪明的事情,比如记录它们的对数(log(.Machine$double.xmin)
是 -708,你可以很容易地记录 这样 小得多的数字)。 R 中的一些 p 值计算允许您检索 log-p 值而不是 p 值,但 Wilcoxon 检验没有这样的功能。
虽然如果您非常需要这种能力,也许可以从头开始构建这种能力,但研究人员通常只会将此类 p 值视为“极小”;如果需要,您可以说“<1e-308” .我见过的唯一一个人们担心如此小的 p 值的精确值的研究领域是生物信息学,其中 p 值本身被视为度量标准,而不是统计清晰度的定性指标差异。
这是一个小示例,它测试样本量逐渐增大的非重叠集的 p 值,显示 p 值减小然后下溢到零(请参见位于下方 y 轴上的点图的右边缘):
w <- function(n=20) {
wilcox.test(1:n,1e6+1:n)$p.value
}
nvec <- seq(20,1000,by=10)
pvec <- sapply(nvec,w)
破解 log-p 值
深入研究 stats:::wilcox.test.default
中的代码,我们可以找到根据测试统计和分组样本大小计算 p 值的位置,并使用 log.p=TRUE
重新计算它们.下面的代码跳过了一些细节,例如考虑关系和允许不同的备选假设(即假设是双侧测试)。
这为您提供了 p 值的 自然 对数;您可以通过乘以 log10(exp(1))
...
wilcox_log_p <- function(x,y,exact=FALSE,correct=TRUE,...) {
## assume two-sided
w <- wilcox.test(x,y,...)
n.x <- length(x)
n.y <- length(y)
STATISTIC <- w$statistic
if (exact) {
if (STATISTIC > (n.x * n.y/2)) {
return(pwilcox(STATISTIC - 1, n.x, n.y,
lower.tail = FALSE, log.p=TRUE))
}
return(pwilcox(STATISTIC, n.x, n.y, log.p=TRUE))
} else {
NTIES <- 0 ## assume no ties!
z <- STATISTIC - n.x * n.y/2
SIGMA <- sqrt((n.x * n.y/12) * ((n.x + n.y + 1) -
sum(NTIES^3 - NTIES)/((n.x + n.y) * (n.x + n.y -
1))))
if (correct) {
CORRECTION <- sign(z) * 0.5
}
z <- (z - CORRECTION)/SIGMA
PVAL <- log(2) + min(pnorm(z, log.p=TRUE),
pnorm(z, lower.tail = FALSE, log.p=TRUE))
return(PVAL)
}
}
w <- function(n=20) {
wilcox.test(1:n,1e6+1:n, exact=FALSE)$p.value
}
w2 <- function(n=20) {
wilcox_log_p(1:n,1e6+1:n)
}
nvec <- seq(20,1100,by=10)
pvec <- sapply(nvec,w)
pvec2 <- sapply(nvec,w2)
dd <- data.frame(n=rep(nvec,2),p=c(log(pvec),pvec2),
method=rep(c("default","log_p"),each=length(nvec)))
library(ggplot2); theme_set(theme_bw())
ggplot(dd, aes(n,p,colour=method)) + geom_point() + geom_line()
scale_x_log10()