来自"数据分析工具的随机数发生器错误"在VBA脚本中使用

时间:2015-08-07 23:38:57

标签: excel vba excel-vba random

我创建了一个执行统计技术引导的VBA脚本。我的原始样本是通过在excel中使用数据分析工具从泊松分布中提取的(因为在泊松分布的excel函数中没有反向构建,我想不出任何其他模拟泊松分布值的方法)。但是,当我运行我的VBA脚本时,我从第一次迭代中得到了这个通知:

"随机数生成 - 输出范围将覆盖现有数据。按OK键覆盖范围内的数据:' [TestCoverage(Poisson,ss50).xlsm] ParametricBootstrap'!$ B $ 2:$ B $ 51"

我知道"覆盖"在使用数据分析工具时需求,因此在运行VBA脚本之前,我总是检查单元格是否为空。但除了检查自己是否清楚之外,我已经在模型中加入了一个特定部分,用于清除问题所指示的单元格内容,就在第一次使用工具之前(第16行),但仍然是VBA脚本的行为就像显示此通知的单元格不为空。当VBA脚本到达第22行(​​数据分析工具的操作)时,它会抛出上一条消息。

奇特的部分是我创建了一个相同的VBA脚本(因为我必须为分布池评估bootstrapping),它使用数据分析工具再次从Normal分布中绘制原始样本,但是那种情况它运作正常。

这是代码:

Sub parametricbootstrappoisson50()

Dim iterations As Integer

iterations = InputBox("Please insert the number of times you want the bootstrapping process to be performed")

Application.ScreenUpdating = False

'These statements clear the results in the Coverage Results sheet existing from previous operations of the macro
Sheets("Coverage Results").Activate
Range("A3").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.ClearContents
Sheets("Parametric Bootstrap").Activate
Range("B2:C51").Select
Selection.ClearContents

For n = 1 To iterations

    'Creates an original sample from a Poisson distribution with parameter lambda P2 (mean)
    Application.Run "ATPVBAEN.XLAM!Random", ActiveSheet.Range("$B$2"), 1, 50, _
    5, , Range("P2").Value

    '1000 bootstrap samples and bootstrap means are produced and stored in the respective cells

    For i = 1 To 1000

        'Creates a bootstrap sample from a Poisson distribution with estimated parameter lambda Q2 (mean)
        Application.Run "ATPVBAEN.XLAM!Random", ActiveSheet.Range("$B$2"), 1, 50, _
        5, , Range("Q2").Value
        Sheets("Parametric Bootstrap").Range("E2").Offset(i, 0).Value = Sheets("Parametric Bootstrap").Range("R2").Value

        'Delete the bootstrap sample produced so that it will not need confirmation to overwrite the data when the next bootstrap sample will be drawn
        Range("C2:C51").Select
        Selection.ClearContents

    Next i

    'This is the process of transferring the results of the bootstrapping process to the Coverage Results sheet
    Sheets("Coverage Results").Range("A1:F1").Offset(n, 0).Value = Sheets("Parametric Bootstrap").Range("I2:N2").Value

    'Indication on whether the population mean is covered from the bootstrap confidence intervals of the nth iteration or not
    If Sheets("Parametric Bootstrap").Range("P2").Value >= Sheets("Coverage Results").Range("C1").Offset(n, 0).Value And Sheets("Parametric Bootstrap").Range("P2").Value <= Sheets("Coverage Results").Range("D1").Offset(n, 0).Value Then
        Sheets("Coverage Results").Range("G1").Offset(n, 0).Value = "Yes"
    Else
        Sheets("Coverage Results").Range("G1").Offset(n, 0).Value = "No"
    End If

    Sheets("Parametric Bootstrap").Activate

    'Delete the original sample produced so that it will not need confirmation to overwrite the data when the next original sample will be drawn
    Range("B2:B51").Select
    Selection.ClearContents

Next n

Application.ScreenUpdating = True

Sheets("Coverage Results").Activate
Range("I2").Select

End Sub

1 个答案:

答案 0 :(得分:0)

这并不是你问题的答案,但我有机会进行模拟,需要模拟泊松随机变量,并为此编写了我自己的用户定义函数。它的工作原理是模拟泊松过程并计算1个单位时间内的到达次数。如果您希望评论标记的行为类似于工作表函数Application.Volatile,请从Rand()移除评论标记,并在电子表格发生任何更改时重新计算。

Function RandPoisson(lambda As Double) As Long
    'Application.Volatile
    Dim count As Long
    Dim x As Double, sum As Double
    Do While True
        x = -Log(Rnd()) / lambda
        If sum + x > 1 Then
            RandPoisson = count
            Exit Function
        Else
            sum = sum + x
            count = count + 1
        End If
    Loop
End Function

为了测试这个,我编写了以下子,并将输出与内置函数Poisson.Dist进行了比较:

Sub test()
    Dim i As Long, p As Long
    Dim counts As Variant

    ReDim counts(0 To 9)
    Randomize
    For i = 1 To 1000000
        p = RandPoisson(3)
        If p < 10 Then counts(p) = counts(p) + 1
    Next i
    For i = 0 To 9
        Range("B2").Offset(i).Value = counts(i) / 1000000
    Next i
End Sub

输出:

enter image description here

即使涉及一百万次模拟,计算也只需要1秒钟。