在 python/numpy/scipy 中生成低差异准随机序列?

问题描述 投票:0回答:4

对此已经存在问题,但答案包含损坏的链接,并且已有两年多了,我希望现在有更好的解决方案:)

低差异准随机序列,例如索博尔序列比均匀随机序列更均匀地填充空间。有没有一种好的/简单的方法在 python 中生成它们?

python numpy random numbers scipy
4个回答
17
投票

我认为 Python 中低差异序列的最佳替代方案是灵敏度分析库 (SALib):

https://github.com/SALib/SALib

我认为这是一个活跃的项目,您可以联系作者检查您需要的功能是否已经实现。如果这不能解决您的问题,Corrado Chisari 将 Matlab(由 John Burkardt)制作的 SOBOL 版本移植到 Python,您可以在这里访问它:

http://people.sc.fsu.edu/~jburkardt/py_src/sobol/sobol.html

有人清理了这些来源中的注释,并将它们放入文档字符串的格式中。它更具可读性,您可以在这里访问它:

https://github.com/naught101/sobol_seq


4
投票

Scipy 现在有这个选项 http://scipy.github.io/devdocs/ generated/scipy.stats.qmc.Sobol.html

PyTorch 还证明了生成 sobol 随机数的选项。它允许的尺寸高达~1k,并且可以选择打开加扰。 https://pytorch.org/docs/stable/ generated/torch.quasirandom.SobolEngine.html


2
投票

我认为现在最简单的方法(从 SciPy 版本 >= 1.7.1 开始)就是我在这里所做的。 它适用于多达 21,201 个维度,因为他们实现了 Joe 和 Kuo 算法,这是您可以获得的最大维度数(开源)。 https://web.maths.unsw.edu.au/~fkuo/sobol/

这里我展示了如何使用base2方法(使用Owen Scrambling)和随机方法(从序列中生成任意数量的点),以及如何跳过第一个点。

请注意,此例程可能非常慢(由于 ndtri 或点到冲击的逆正态分布转换),特别是在高维度 + 高模拟计数中。 从 Sobol 序列本身生成点非常快,但对于大多数蒙特卡罗模拟,您将它们转换为冲击(您可能使用标准正态分布之外的另一种分布)。 这至少可以让你直接用 Python 代码生成点。

另外,在 QMCgenerate 例程中,我跳过了第一个点(即 0)——虽然这很常见,但有些论文建议不要这样做(但我还没有看到一个好的替代方案,如果你有的话,感觉自由评论)。 我转置它们只是为了稍后可以将它们粘贴到 Excel 中并检查生成的冲击。 不管怎样,希望那些需要这个算法的人觉得它很有用。

from scipy.stats import qmc # needs SciPy >= 1.7.1
from scipy.special import ndtri
import numpy as np
import timeit

time_periods = 252
factors = 12

# IF using base2 generation, need a pow(2,m)
sims = 8192 

dimensions = factors*time_periods

def RQMCgenerate (dimensions, sims, seed):
    start_time = timeit.default_timer()
    m=10 # start at 1024 sims
    while pow(2,m) < sims: #m = 17 # 131,072 sims; M = 16 # 65,536 sims
        m = m+1
    RQMCgenerator = qmc.Sobol(dimensions, scramble=True, seed=seed)
    RQMCsamples = RQMCgenerator.random_base2(m)
    print('\n' + 'Time after sample generation RQMC:', (timeit.default_timer() - start_time), 'seconds'); 
    sobol = ndtri(RQMCsamples).T # get normsinv(points) and transpose to dimensions * sims 
    del RQMCsamples
    print('\n' + 'Time after ndtri (normsinv) of', sims,'sims x dimensions', dimensions, 'Randomized Sobol points): ', (timeit.default_timer() - start_time), 'seconds');
    return sobol

def QMCgenerate(dimensions, sims):
    start_time = timeit.default_timer()
    QMCgenerator = qmc.Sobol(dimensions, scramble=False)
    QMCgenerator.fast_forward(1) #skip first point where normsinv(0) = -Inf
    QMCsamples = QMCgenerator.random(sims) #this generates points not having to be powers of 2
    print('\n' + 'Time after sample generation QMC:', (timeit.default_timer() - start_time), 'seconds'); 
    sobol = ndtri(QMCsamples).T # get normsinv(points) and transpose to dimensions * sims
    del QMCsamples
    print('\n' + 'Time after ndtri (normsinv) of', sims,'sims x dimensions', dimensions, 'Sobol points):', (timeit.default_timer() - start_time), 'seconds');
    return sobol

RQMCsobol = RQMCgenerate(dimensions, sims, seed=0) #note sims changed with pow(2,m) if a power of 2 was not passed
sobol = QMCgenerate(dimensions, sims)

样本生成后的时间RQMC:0.4269224999952712秒

8092 sims x 维度 3024 随机 Sobol 点的 ndtri (normsinv) 之后的时间:1.0048970999996527 秒

样本生成QMC后的时间:0.0630135999963386秒

8092 sims x 维度 3024 Sobol 点的 ndtri (normsinv) 之后的时间:0.5444753999981913 秒

在更高的 sims* 维度上,这会变得慢得多,尽管我还没有发现比 Python 中的 ndtri 更快的点到正态分布冲击的转换:

样本生成 RQMC 后的时间:2.1779929000040283 秒

131072 sims x 维度 3024 随机 Sobol 点的 ndtri (normsinv) 之后的时间:10.617904700004146 秒

样本生成 QMC 后的时间:1.079756200000702 秒

131072 sims x 维度 3024 Sobol 点的 ndtri (normsinv) 之后的时间:9.545934699999634 秒


1
投票

Chaospy 也是一个有效的选项。人们可以选择多种低差异采样方法(包括“Sobol”、拉丁超立方体等) - 有关更多详细信息,请参阅文档

© www.soinside.com 2019 - 2024. All rights reserved.