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

zxlwwiss  于 2022-11-10  发布在  Python
关注(0)|答案(4)|浏览(241)

这上面有already a question,但是答案包含一个断开的链接,而且已经两年多了,我希望现在有一个更好的解决方案:)
低差异的准随机序列,例如Sobol序列,比均匀随机序列更均匀地填充空间。有没有好的/简单的方法在python中生成它们?

iyzzxitl

iyzzxitl1#

我认为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
有人清理了这些源代码中的注解,并将其转换为docstring格式。这样可读性更强,您可以在这里访问它:
https://github.com/naught101/sobol_seq

ogsagwnx

ogsagwnx2#

Scipy现在有此选项http://scipy.github.io/devdocs/generated/scipy.stats.qmc.Sobol.html
PyTorch还证明了生成sobol随机数的选项。它允许高达~ 1 k的维数,并具有打开加扰的选项。https://pytorch.org/docs/stable/generated/torch.quasirandom.SobolEngine.html

bweufnob

bweufnob3#

Chaospy也是一个有效的选项。人们可以选择几种方法进行低差异采样(包括'Sobol,拉丁超立方体等)-更多细节请参见the documentation

k75qkfdt

k75qkfdt4#

我认为现在最简单的方法(SciPy版本〉= 1.7.1)就是我在这里做的。它适用于多达21,201个维度,因为他们实现了Joe和Kuo算法,这是你能得到的最大维度数(开源)。https://web.maths.unsw.edu.au/~fkuo/sobol/
这里我将展示如何使用base 2方法(使用Owen Scrambling)和random方法(从序列中生成任意数量的点),以及如何跳过第一个点。
请注意,此例程可能非常慢(由于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西姆斯x维度3024随机Sobol点ndtri(normsinv)后的时间:1.0048970999996527秒
样本生成QMC后的时间:0.0630135999963386秒
8092西姆斯x尺寸3024索Perl点的ndtri(normsinv)后的时间:0.5444753999981913秒
在更高的西姆斯 * 维度上,这个过程会变得更慢,尽管我还没有找到比Python中的ndtri更快的将点转换为正态分布冲击的方法:
样本生成后的时间RQMC:2.1779929000040283秒
131072个西姆斯x维度3024个随机Sobol点的ndtri(normsinv)后时间:10.617904700004146秒
样本生成QMC后的时间:1.079756200000702秒
131072西姆斯x尺寸3024索Perl点的ndtri(normsinv)后的时间:9.545934699999634秒

相关问题