|
R中的ks.test检验确实有点不靠谱。也许是个人水平不够,该函数用起来非常不顺手。我主要用wilcox.test来检验均匀分布。举个例子:先随机产生500个数,每个数的取值范围是:大于等于1且小于等于10,这500个数都为整数。现在要求检验这500个数是否符合均匀分布。假设这500个数存于向量x中,那么,产生一组与其长度差不多的向量y,其中也同为整数,且依据均匀分布产生1到10之间的数字。之后用wilcox.test(x,y)检测两组数据的均值是否存在显著不同(p值小于临界值则认为不同),由于该函数不事先假设样本的分布,所以更贴近实际情况。但是,光做一次比较不能说明问题:即使此次检验p值很大,也不能说x就服从均匀分布。均匀分布有个特点:
比如均匀分布产生的向量z=(2,1,3,4,5,9,8,6,7,10, ...) ---->将所有数字全部加1,超过10的再用1替代,形成“环形位移”---->形成新的向量z' = (3,2,4,5,6,10,9,7,8,1, ...) : z与z' 的均值应该都差不多!当然,在这个例子中两者是相等的,实际例子中会有些许差异,但相差不会太大,原因是——总共10个档位(取值范围是1-10),无论你怎么交换每个档位代表的数值大小,每个档位上聚集的数字个数彼此都差不多。比如500个数字,分到10个档位,每个档平均有500/10 = 50个左右的数字。因此,就算是在z' 的基础上再进行“环形位移”,产生z'',并在此基础上再位移,产生z''',它们彼此的均值水平都相差无几!
如果向量z并不服从均匀分布呢?比如z = (3,3,3,3,3,3,3,3),那么位移后为z' = (4,4,4,4,4,4,4,4),均值差异明显,更不要说拿几轮位移之后的z'''和z去比较了。
因此,检验均匀分布,除了运行wilcox.test(x,y),还要运行wilcox.test(x',y), wilcox.test(x'',y), wilcox.test(x''',y), ...位移要进行9次(档位总共只有10档,第10次位移就又变回向量x了,所以没有必要再做了),检验也要多进行9次,再加上第一次检验,如果10次中有比如9次能通过(理想情况是10次全过),则说明向量x中的数据很大可能性是来自均匀分布!
程序如下:
# mov为环形位移程序(是unif.test的子函数),参数列表如下:
# x : 需要位移的数据向量
# maxValue : x中数据若加1后超过该数,就会调成最小值(例子中maxValue为10,最小值系统会自动计算,此处为1)
# n : 档位数,由于每个整数随机变量取值范围是1-10,故档位总共有10个
# 函数会返回一个与x等长的向量,它是环形位移1位之后的结果
mov <- function(x, maxValue, n) {
x = x + 1
x[which(x > maxValue)] = x[which(x > maxValue)] - n
return(x)
}
# 均匀分布检验程序unif.test,参数列表如下:
# x : 需进行均匀分布检验的数据向量
# n : 档位数,调用函数时若第二位不写,则默认为10
# alpha : 判断p值是否过小的临界值,调用函数时若第三位不写,则默认为0.1,p值小于该数,则视为x均值与y显著不同
# 函数返回一个小数,该小数是用n次测试中成功的次数(即x或其位移向量与y均值大体相同)除以总测试次数n所得到的比例
# 按上例,该数应大于等于0.9,即10次中至少要有9次成功才可以,否则就太不像话了,不能承认x是服从均匀分布的
# 函数用法:unif.test(x) ---> 只给出待检验向量,后面空着,则n默认为10,alpha默认为0.1,当然,也可赋其他值,比如:
# unif.test(x, 100, 0.05),但在题目所给情形下这样定参数是没道理的
unif.test <- function(x, n = 10, alpha = 0.1) {
max.x = max(x)
rep.y = round(length(x) / n)
if (rep.y < 2) rep.y = 2
y = rep((max.x - n + 1):max.x, rep.y) # -------> 产生标准样本y
result = 0
for (i in 1:n) {
x = mov(x, max.x, n)
wt = wilcox.test(x, y) # -----> 默认双侧检验
if (wt$p.value > alpha) result = result + 1
}
return(result/n)
}
测试:
> x = ceiling(runif(500)*10) # --------> 产生500个整数随机变量,每个的取值范围是1-10,这里用均匀分布产生随机数
> unif.test(x)
[1] 1
结果是合格的,数据符合均匀分布
如果产生整数随机数时使用正态分布,那么检验结果如何?
> z = seq(from = -3, to = 3, by = 0.6)
> p = diff(pnorm(z))
> p[5] = p[5] + pnorm(-3)
> p[6] = p[6] + pnorm(-3)
> x = sample(1:10, 500, replace = TRUE, prob = p) # -------> 其中的p表示1到10出现的概率,它是正态分布对应的概率
> unif.test(x)
[1] 0.2
结果明显不合格,样本不符合均匀分布
|