在Excel中加速蒙特卡罗

在Excel中加速蒙特卡罗,excel,vba,random,montecarlo,Excel,Vba,Random,Montecarlo,我正在Excel中运行Monte Carlo。为了表示每个月每个产品SKU的需求分布,我使用了以下公式500次: =IFERROR(BETA.INV(RAND(),(1+4*(D35-D31)/(D27-D31)),(1+4*(D27-D35)/(D27-D31)),D31,D27),0) 因此,一次超过500个RAND()volatile函数 公式每次迭代的输出存储在表中。我有一个VBA来处理这个问题: Sub QARLO_Products() 'runs on QARLO_P!, for f

我正在Excel中运行Monte Carlo。为了表示每个月每个产品SKU的需求分布,我使用了以下公式500次:

=IFERROR(BETA.INV(RAND(),(1+4*(D35-D31)/(D27-D31)),(1+4*(D27-D35)/(D27-D31)),D31,D27),0)

因此,一次超过500个
RAND()
volatile函数

公式每次迭代的输出存储在表中。我有一个VBA来处理这个问题:

Sub QARLO_Products()
'runs on QARLO_P!, for forecasting product
    Range("Q7:OC100000").ClearContents
    For Iteration = 1 To Range("G1").Value
        Range("I1").Value = Range("G1").Value - Iteration
        'For QMIN Zinc-Bulk
        Cells(6 + Iteration, 17) = Iteration
        Cells(6 + Iteration, 18) = Cells(39, 4)
        Cells(6 + Iteration, 19) = Cells(39, 5)
        Cells(6 + Iteration, 20) = Cells(39, 6)
        Cells(6 + Iteration, 21) = Cells(39, 7)
        Cells(6 + Iteration, 22) = Cells(39, 8)
        Cells(6 + Iteration, 23) = Cells(39, 9)
        Cells(6 + Iteration, 24) = Cells(39, 10)
        Cells(6 + Iteration, 25) = Cells(39, 11)
        Cells(6 + Iteration, 26) = Cells(39, 12)
        Cells(6 + Iteration, 27) = Cells(39, 13)
        Cells(6 + Iteration, 28) = Cells(39, 14)
        Cells(6 + Iteration, 29) = Cells(39, 15)
        'For QMIN Zinc-Jugs
        Cells(6 + Iteration, 30) = Iteration
        Cells(6 + Iteration, 31) = Cells(40, 4)
.... blah, blah, blah and so on for all products....
        Cells(6 + Iteration, 444) = Cells(561, 14)
        Cells(6 + Iteration, 445) = Cells(561, 15)
   Next Iteration
End Sub
这些语句的左侧表示记录输出数据的表位置,右侧表示上述公式的输出

我注意到这个VBA贯穿了系列中的每一行。每行都会导致所有500个volatile
RAND()
函数重新计算。在核心i7/32GB RAM的所有8个核心上,此VBA的一次迭代需要30秒。我想定期运行5000次迭代

你能建议一些方法使这个模型更有效地运行吗

  • 将一个单元格设为
    RAND()
    ,然后让所有500个单元格都引用它
  • 重组VBA
我已经做了所有基本/常规的事情,以使Excel更高效地运行。

你说“我已经做了所有基本/常规的事情,以使Excel更高效地运行”是什么意思?你是否尝试过打开屏幕更新等等

Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False

'Place your macro code here

Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True

<>如果你想让Excel更有效率,你必须考虑在VBA中完全运行蒙特卡洛模拟。将结果存储在一个数组中,并在所有模拟结束时将其绘制在excel表格中。

一个小的更改可能会产生很大的差异

通过对数组的单次调用读取和写入较大的范围。 我现在查不到确切的密码,但你可以说

   Range(Cells(6 + Iteration, 18), Cells(6+Iteration, 455).Value = Range(Cells(39,4), Cells(561,15).Value
或者通过拆分读写操作,以便可以在调试器中进行检查

   Dim TempValues As Variant ' Really a 2D array of variants

   TempValues = Range(Cells(39,4), Cells(561,15)).Value
   Range(Cells(6 + Iteration, 18), Cells(6 + Iteration, 455)).Value = TempValues
通过这样做,您将一次读取/写入所有内容,如果只写入一次,您将迫使易失性计算发生一次,而不是每次写入

这看起来像是一篇关于读取和写入数组范围以及在调试器下检查内容的精彩文章:

其他一些想法:

  • 在VBA中将volatile函数替换为您自己的rand函数(可能只是在内部调用
    Rnd
    )。然后,当您明确地重新计算所有值时,if将仅获取值(并重新计算)
  • 在“记录”循环过程中,将工作表切换为手动计算,以防止在写入工作表时易失性单元格进行计算

@pizzettix我指的是像这样的基础知识。你的屏幕更新脚本是高级的(对我来说)