什么是拉丁超立方抽样法?它和蒙特卡罗模拟有什么关系?

逆变换方法(The Inverse Transform Method)采样

拉丁超立方抽样

拉丁超立方抽样(LHS)是一种从多维分布中生成参数值的近随机样本的统计方法。抽样方法常用于构建计算机实验或进行蒙特卡罗积分。在统计抽样的上下文中,当(且仅当)每行和每列只有一个样本时,包含样本位置的方格为拉丁方格。拉丁超立方体是将这个概念推广到任意数量的维数,因此每个样本是包含它的每个轴向超平面上的唯一一个样本。

在简单随机抽样中,不考虑之前生成的样本点,生成新的样本点。我们并不需要事先知道需要多少采样点。

在拉丁超立方抽样中,首先必须决定使用多少采样点,并且记住每个采样点是在哪一行和哪一列中采样的。请注意,这种配置类似于在不互相威胁的情况下,在棋盘上有N辆車。

拉丁超立方抽样也是蒙特卡洛模拟法的一种,它改进了采样策略能够做到以较小的采样规模获得较高的采样精度,在实际应用中具有高效性很受欢迎。核心步骤为分层抽样、打乱排序。

在累积分布函数中,分层抽样先将取值空间[0,1]做N等分,得到[0,1/N], [1/N,2/N], …, [(N-1)/N,N]这N个子层,在每层中随机选取采样点,取反得到N个采样值 matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园 ,…, matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园排序会打乱采样值的顺序,避免出现第一层抽第一个样本、第i层抽第f(x)个样本这种尴尬无意有规律的场面,保持了样本间的独立性。
 
(注意CDF的值总是位于区间[0, 1])
 

对于m个不同输入随机变量,分层采样可以得到mxN个采样值,样本常以样本矩阵的形式代入模型中进行进一步试验。分层采样的样本值能够覆盖输入随机变量的整个分布区间,“抽样不替换”,样本重复少;相比蒙特卡罗模拟法的简单随机采样,拉丁超立方抽样法产生样本的空间覆盖率更高,其本质就是样本的标准差较小。

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

概率密度函数PDF和累计概率密度函数CDF

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

  拉丁超立方抽样原理示意图

蒙特卡罗抽样技术完全是随机的,即在输入分布的范围内,样本可以落在任何位置。样本更有可能从高发生概率的分布区域中抽取。在累积分布中,每个蒙特卡罗样本使用一个0 和 1之间的新的随机数。在足够的迭代之后,蒙特卡罗抽样通过抽样“重建”输入分布。但是,当执行的迭代次数少的时候,会产生聚集的问题。

拉丁超立方体抽样是抽样技术的最新进展,和蒙特卡罗方法相比,它被设计成通过较少迭代次数的抽样,准确地重建输入分布。拉丁超立方体抽样的关键是对输入概率分布进行分层。分层在累积概率尺度(0,1.0)上把累积曲线分成相等的区间。然后,从输入分布的每个区间或“分层”中随机抽取样本。抽样被强制代表每个区间的值,于是,被强制重建输入概率分布。

假设我们要在n维向量空间里抽取m个样本。拉丁超立方体抽样的步骤是:

(1)将每一维分成互不重迭的m个区间,使得每个区间有相同的概率
(通常考虑一个均匀分布,这样区间的长度相同)。

(2)在每一维里的每一个区间中随机的抽取一个点;

(3)再从每一维里随机抽出(2)中选取的点,将它们组成向量。

在抽样时,每个区间都抽取一个样本。使用拉丁超立方体方法,样本更加准确地反映输入概率分布中值的分布。在拉丁超立方体抽样中使用的技术是“抽样不替换”,累积分布的分层数目等于执行的迭代次数。

 

 

简单总结一下: 由此可见这个逆采样变换方法还是很牛逼的,只要你能求出随机变量X的cdf,基本上就能用均匀分布生成它。缺点是要能求出随机变量X的cdf。
 
 

matlab实现拉丁超立方抽样(逆变换法)

1. 从离散均匀分布U[1, 1024]中抽样10000个点

x = unidinv(linspace(0+eps, 1, 10000), 1024);
idx = randperm(length(x));
y = x(idx);

figure
plot(y, '.')

figure
plot(unique(x), 'o')
xlim([0, 1024])

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

抽样结果

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

 抽样结果区间分布

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

 直方图(binwidth=3)

 可以看到拉丁超立方的好处是覆盖率高(因为这里即使仅抽取1024个点,也能覆盖整个抽样区间)。

2. 从高斯分布N(5, 3)中抽样

x = norminv(linspace(0+eps, 1, 10000), 5, 3);
idx = randperm(length(x));
y = x(idx);

figure
plot(y, '.')

figure
histogram(y, 'binwidth', 0.1)

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

抽样结果

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

直方图(binwidth=0.1)

 3. matlab中常用分布的PDF、CDF和逆CDF

可以看到逆变换法需要用到CDF的逆,这里给出matlab中常见的概率分布。

来自:https://blog.csdn.net/leo2351960/article/details/39207299/

统计工具箱函数
Ⅰ-1        概率密度函数
函数名        对应分布的概率密度函数
betapdf        贝塔分布的概率密度函数
binopdf        二项分布的概率密度函数
chi2pdf        卡方分布的概率密度函数
exppdf        指数分布的概率密度函数

evpdf         最大值型的极值I型分布(Gumbel分布)
fpdf        f分布的概率密度函数
gampdf        伽玛分布的概率密度函数
geopdf        几何分布的概率密度函数
hygepdf        超几何分布的概率密度函数
normpdf        正态(高斯)分布的概率密度函数
lognpdf        对数正态分布的概率密度函数
nbinpdf        负二项分布的概率密度函数
ncfpdf        非中心f分布的概率密度函数
nctpdf        非中心t分布的概率密度函数
ncx2pdf        非中心卡方分布的概率密度函数
poisspdf        泊松分布的概率密度函数
raylpdf        雷利分布的概率密度函数
tpdf        学生氏t分布的概率密度函数
unidpdf        离散均匀分布的概率密度函数
unifpdf        连续均匀分布的概率密度函数
weibpdf        威布尔分布的概率密度函数

Ⅰ-2  累加分布函数
函数名        对应分布的累加函数
betacdf        贝塔分布的累加函数
binocdf        二项分布的累加函数
chi2cdf        卡方分布的累加函数
expcdf        指数分布的累加函数

evcdf         最大值型的极值I型分布(Gumbel)的累加函数
fcdf        f分布的累加函数
gamcdf        伽玛分布的累加函数
geocdf        几何分布的累加函数
hygecdf        超几何分布的累加函数
logncdf        对数正态分布的累加函数
nbincdf        负二项分布的累加函数
ncfcdf        非中心f分布的累加函数
nctcdf        非中心t分布的累加函数
ncx2cdf        非中心卡方分布的累加函数
normcdf        正态(高斯)分布的累加函数
poisscdf        泊松分布的累加函数
raylcdf        雷利分布的累加函数
tcdf        学生氏t分布的累加函数
unidcdf        离散均匀分布的累加函数
unifcdf        连续均匀分布的累加函数
weibcdf        威布尔分布的累加函数

 

Ⅰ-3  累加分布函数的逆函数
函数名        对应分布的累加分布函数逆函数
betainv        贝塔分布的累加分布函数逆函数
binoinv        二项分布的累加分布函数逆函数
chi2inv        卡方分布的累加分布函数逆函数
expinv        指数分布的累加分布函数逆函数

evinv         Gumbel分布的逆函数
finv        f分布的累加分布函数逆函数
gaminv        伽玛分布的累加分布函数逆函数
geoinv        几何分布的累加分布函数逆函数
hygeinv        超几何分布的累加分布函数逆函数
logninv        对数正态分布的累加分布函数逆函数
nbininv        负二项分布的累加分布函数逆函数
ncfinv        非中心f分布的累加分布函数逆函数
nctinv        非中心t分布的累加分布函数逆函数
ncx2inv        非中心卡方分布的累加分布函数逆函数
icdf       
norminv        正态(高斯)分布的累加分布函数逆函数
poissinv        泊松分布的累加分布函数逆函数
raylinv        雷利分布的累加分布函数逆函数
tinv        学生氏t分布的累加分布函数逆函数
unidinv        离散均匀分布的累加分布函数逆函数
unifinv        连续均匀分布的累加分布函数逆函数
weibinv        威布尔分布的累加分布函数逆函数

  

 4. python库pyDOE

pyDOE是python环境下进行试验设计的包。

可以进行拉丁超立方抽样

https://pythonhosted.org/pyDOE/randomized.html#latin-hypercube

https://github.com/tisimst/pyDOE

https://github.com/clicumu/pyDOE2

基本语法

from pyDOE import lhs

lhs(n, [samples, criterion, iterations])
# n: 维度, integer
# samples:采样点数, integer
# criterion:default "None" 
# 一个告诉 lhs 如何采样点的字符串(默认值:无,它只是随机化间隔内的点)
# “center”或“c”:将采样间隔内的点居中
# “maximin”或“m”:最大化点之间的最小距离,但将点放在其间隔内的随机位置
# “centermaximin”或“cm”:与“maximin”相同,但在间隔内居中
# “correlation”或“corr”:最小化最大相关系数



# 输出设计将所有变量范围从零缩放到一,然后可以根据用户的意愿进行转换
#(例如使用 scipy.stats.distributions ppf(逆累积分布)函数转换为特定的统计分布。

  

抽样

例如,二维标准高斯分布抽样:

>>> from scipy.stats import norm
>>> lhd = lhs(2, samples=5)
>>> lhd = norm(loc=0, scale=1).ppf(lhd)  # this applies to both factors here

Out[28]:
array([[ 0.75863463, -0.3369805 ],
[-0.00529301, 0.99955206],
[-1.07653807, -0.1303521 ],
[-0.36624876, 0.3676775 ],
[ 0.8589196 , -0.85595459]])

matlab和python中进行拉丁超立方抽样(逆变换法)-冯金伟博客园

  拉丁超立方抽样原理示意图

计算过程也很直观,首先基于cdf的逆进行分层区间抽样,然后通过期望分布函数进行变换即可。

python环境下的统计分布从scipy.stats包导入。包括连续分布和离散分布。累计分布的逆采用ppf()得到。

https://docs.scipy.org/doc/scipy/tutorial/stats.html

pdf()

Probability density function.

cdf()

Cumulative distribution function.

ppf()

Percent point function (inverse of cdf — percentiles).

从离散分布中抽样也是一样:

from scipy.stats import randint
lhd = lhs(6, samples=10)
lhd = randint(0, 5).ppf(lhd) # sample from U[0, 5)

Out[31]:
array([[1., 1., 2., 1., 3., 2.],
[4., 0., 1., 3., 1., 3.],
[2., 3., 2., 2., 2., 4.],
[2., 4., 0., 4., 4., 1.],
[3., 3., 3., 2., 0., 1.],

可以指定在每个区间采样的准则:

lhs(4, criterion='center')
array([[ 0.875,  0.625,  0.875,  0.125],
       [ 0.375,  0.125,  0.375,  0.375],
       [ 0.625,  0.375,  0.125,  0.625],
       [ 0.125,  0.875,  0.625,  0.875]])

  

还可以为每个维度指定不同的分布参数:

例如,现在,假设我们想将这些设计转换为正态分布,均值=[1,2,3,4],标准差= [0.1,0.5,1,0.25]: 

>>> design = lhs(4, samples=10)
>>> from scipy.stats.distributions import norm
>>> means = [1, 2, 3, 4]
>>> stdvs = [0.1, 0.5, 1, 0.25]
>>> for i in xrange(4):
...     design[:, i] = norm(loc=means[i], scale=stdvs[i]).ppf(design[:, i])
...
>>> design
array([[ 0.84947986,  2.16716215,  2.81669487,  3.96369414],
       [ 1.15820413,  1.62692745,  2.28145071,  4.25062028],
       [ 0.99159933,  2.6444164 ,  2.14908071,  3.45706066],
       [ 1.02627463,  1.8568382 ,  3.8172492 ,  4.16756309],
       [ 1.07459909,  2.30561153,  4.09567327,  4.3881782 ],
       [ 0.896079  ,  2.0233295 ,  1.54235909,  3.81888286],
       [ 1.00415   ,  2.4246118 ,  3.3500082 ,  4.07788558],
       [ 0.91999246,  1.50179698,  2.70669743,  3.7826346 ],
       [ 0.97030478,  1.99322045,  3.178122  ,  4.04955409],
       [ 1.12124679,  1.22454846,  4.52414072,  3.8707982 ]])

  

快去成为你想要的样子!