我正在试图测试Excel的随机生成器是否随机,这就是我使用Wald's test的原因
通过这样做,我得到了p值为0,因此我不接受零假设,即样本不是随机的。
我的问题是:
1)我在编码或解释时犯了一些错误吗?
代码:
'By Julio Jesús Luna moreno
'jlqmoreno@gmail.com
Option Base 1
Sub WALDTEST()
Dim x, r(), i, n, mu, sigma, plus(), minus(), k, h, f, j, phi, rplus, rminus, rachas() As Variant
Dim w As Double, flag As Boolean
n = 1000: k = 0: h = 0: flag = False: rplus = 0: rminus = 0: j = 0: phi = 0
Set f = Application.WorksheetFunction
ReDim r(n)
For i = 1 To n
Randomize
x = Rnd()
r(i) = IIf(x >= 0.5, 1, 0)
Debug.Print r(i)
Next i
k = r(1)
h = 2
Do While h <= n
Do Until flag = True Or h > n
If r(h) = k Then
phi = phi + 1
flag = False
h = h + 1
Else
flag = True
k = r(h)
h = h + 1
End If
Loop
If phi >= 1 Then
j = j + 1
ReDim Preserve rachas(j)
rachas(j) = r(h - 2)
Debug.Print rachas(j)
End If
flag = False
phi = 0
Loop
rplus = j - f.Sum(rachas)
rminus = j - rplus
mu = ((2 * rplus * rminus) / j) + 1
sigma = (mu - 1) * (mu - 2) / (j + 1)
w = f.Norm_S_Dist((j- mu)/Sqr(sigma), False)
Debug.Print w
End Sub
提前致谢!
答案 0 :(得分:1)
Excel的随机数生成器不是随机的 - 它只是伪随机数。 (与大多数计算机生成的随机数一样。)
虽然随机数通常在大多数情况下都是随机数,但如果您编写一些代码,您可以看到数字的非随机性如下:
Sub RndTest()
Dim r(0 To 9999, 0 To 9999) As Long
Dim i As Long
Dim x As Long
Dim y As Long
For i = 1 To 100000000
x = Int(Rnd() * 10000)
y = Int(Rnd() * 10000)
r(x, y) = r(x, y) + 1
Next
Cells(1, 1).Resize(10000, 10000).Value = r
Columns("A:NTP").AutoFit
End Sub
运行该代码时需要有点耐心,因为它会生成100,000,000对随机数并将它们分配给100,000,000个单元。但最终产生的模式非常好看。
很多问题是由于VBA中产生的随机数只是一个Single
精度数,只包含大约6位有效数字。
答案 1 :(得分:1)
您需要对代码进行更正。您对mu的计算不正确。
mu = ((2 * f.Count(plus) + f.Count(minus)) / n) + 1
应该是
mu = ((2 * f.Count(plus) * f.Count(minus)) / n) + 1
^
Note the change here
我认为你的randomize命令也应该在for / next循环之外和之前发生。我不确定这会对结果产生什么影响。
答案 2 :(得分:1)
这是如何实施的。
1-我们计算运行次数;每次观察到拾取值的翻转时递增
2-我们检查对应于独立假设(零假设)的正态分布的结果运行次数。确切地说,我们希望获得的运行次数的概率是&#34;那么远#34;从平均水平。注意:它是双尾测试
3-要计算此概率,您应使用累积正态分布,即将参数cumulative
设置为true
Sub WaldWolfowitz()
Randomize
Dim nRuns As Long ' counts the number of runs
Dim x As Long ' a randomly picked value, 0 or 1
Dim lastX As Long: lastX = -1 ' memorizes the last picked value to count runs
Dim N(0 To 1) As Long ' array holds the number of picks of 0 and 1
Dim i As Long, r As Double
For i = 1 To 1000000
r = Rnd
x = IIf(r < 0.5, 0, 1)
N(x) = N(x) + 1
If x <> lastX Then nRuns = nRuns + 1
lastX = x
Next
' Distribution of the number of runs in the case
' the picks are independent (the null hypothesis)
Dim mu As Double, variance As Double, sigma As Double, p As Double, z As Double
mu = 1 + ((2 * N(0)) / (N(0) + N(1))) * N(1) ' rewrote it this way to avoid overflow
variance = (mu - 1) * (mu - 2) / (N(0) + N(1) - 1)
sigma = Sqr(variance)
' The p-test. We calculate the likelihood that the resulted number of runs
' be "that far" from mu. Notice in the calculation below:
' - We compute the absolute value of diff because it's a "two-tailed test"
' - We calculate the "tail" area under the normal curve from that point
' and we multiply it by two
' - The parameter "Cumlative:=True" for Norm_S_Dist to calculate the area under the normal curve
z = Abs(nRuns - mu) / sigma
p = 2 * (1 - WorksheetFunction.Norm_S_Dist(z, True))
Debug.Print mu, sigma, nRuns, z, p
End Sub
P.S。我会留给你运行测试并解释它们。我自己的测试并没有拒绝零独立假设,尽管我对它们并不满意......
答案 3 :(得分:0)
您也可以通过掷硬币进行测试。
以下是测试此功能的快速代码(不是最好的,但按预期工作):
Sub flip()
Dim coin, i, j, zero, one, totalzero, totalone As Long
Dim averagezero, averageone As Double
For i = 1 To 100
For j = 1 To 100
coin = WorksheetFunction.RandBetween(0, 1)
If Value = 0 Then
zero = zero + 1
ElseIf Value = 1 Then
one = one + 1
End If
Next j
totalzero = totalzero + zero
totalone = totalone + one
zero = 0
one = 0
Next i
averagezero = totalzero / 100
averageone = totalone / 100
Debug.Print "Average Zero Count: " & averagezero
Debug.Print "Average One Count: " & averageone
End Sub