随机数生成和在统计模拟中的应用

上传人:xmg****18 文档编号:121250260 上传时间:2020-02-19 格式:DOC 页数:19 大小:239.16KB
返回 下载 相关 举报
随机数生成和在统计模拟中的应用_第1页
第1页 / 共19页
随机数生成和在统计模拟中的应用_第2页
第2页 / 共19页
随机数生成和在统计模拟中的应用_第3页
第3页 / 共19页
随机数生成和在统计模拟中的应用_第4页
第4页 / 共19页
随机数生成和在统计模拟中的应用_第5页
第5页 / 共19页
点击查看更多>>
资源描述

《随机数生成和在统计模拟中的应用》由会员分享,可在线阅读,更多相关《随机数生成和在统计模拟中的应用(19页珍藏版)》请在金锄头文库上搜索。

1、. . .随机数生成及其在统计模拟中的应用黄湘云 关键词:随机数; 统计检验; 模拟 审稿:郎大为、边蓓蕾;编辑:吴佳萍揭秘统计软件如 R,Octave,Matlab 等使用的随机数发生器,然后做一些统计检验,再将其应用到独立随机变量和的模拟中,最后与符号计算得到的精确结果比较。除特别说明外,文中涉及到的随机数都是指伪随机数,发生器都是指随机数发生器。背景随机数的产生和检验方法是蒙特卡罗方法的重要部分,另外两个是概率分布抽样方法和降低方差提高效率方法。在 20 世纪 40 年代中期,当时为了原子弹的研制,乌拉姆(S.Ulam)、冯诺依曼(J.von Neumann) 和梅特罗波利斯(N. Me

2、tropolis) 在美国核武器研究实验室创立蒙特卡罗方法。当时出于保密的需要,与随机模拟相关的技术就代号 “蒙特卡罗”。早期取得的成果有产生随机数的平方取中方法,取舍算法和逆变换法等。这两个算法的内容见统计之都王夜笙的文章。随机数生成讲随机数发生器,不得不提及一个名为 Mersenne Twister(简称 MT)的发生器,它的周期长达 2199371,现在是R 、Octave 和 Matlab等软件(较新版本)的默认随机数发生器。Matlab通过内置的rng函数指定不同的发生器,其中包括1995年Matlab采用 George Marsaglia 在1991年提出的借位减(subtract

3、 with borrow,简称SWB)发生器。在Matlab中,设置如下命令可指定发生器及其状态,其中1234是随机数种子,指定发生器的状态,目的是重复实验结果,v5uniform是发生器的名字。rng(1234, v5uniform) Octave 通过内置的rand函数指定发生器的不同状态,为获取相同的两组随机数,state 参数得设置一样,如1234(你也可以设置为别的值)。Octave已经放弃了老版本内置的发生器,找不到命令去指定早期的发生器,这个和 Matlab 不一样。rand (state,1234)rand(1,5) 0.9664535 0.4407326 0.0074915

4、0.9109760 0.9392690rand (state,1234)rand(1,5) 0.9664535 0.4407326 0.0074915 0.9109760 0.9392690Python的numpy模块也采用MT发生器,类似地,通过如下方式获得相同的两组随机数import numpy as npa = np.random.RandomState(1234)a.rand(5)array( 0.19151945, 0.62210877, 0.43772774, 0.78535858, 0.77997581)a = np.random.RandomState(1234)a.rand(

5、5)array( 0.19151945, 0.62210877, 0.43772774, 0.78535858, 0.77997581)R的默认发生器也是 MT 发生器,除了设置随机数种子的 seed 参数,还可以通过kind参数指定其他发生器,normal.kind参数指定产生正态分布随机数的发生器,下面也使用类似的方式产生两组完全一样的随机数。set.seed(seed, kind = NULL, normal.kind = NULL)set.seed(1234,kind = Mersenne-Twister, normal.kind = Inversion) # 默认参数设置runif(

6、5)1 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154set.seed(1234,kind = Mersenne-Twister, normal.kind = Inversion) # 默认参数设置runif(5)1 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154SWB发生器中“借位相减”步骤是指序列的第i个随机数zi要依据如下递推关系产生,zi=zi+20zi+5b下标i,i+20,i+5都是对32取模的结果,zi+20与zi+5做减法运算,b是借位,其取值与前一步有关,当zi是正值时,下

7、一步将b置为0,如果计算的zi是负值,在保存zi之前,将其值加1,并在下一步,将b的值设为 253。下面关于随机数生成的效率和后面的统计检验,都以生成224个为基准,是1600多万个,取这么多,一方面为了比较编程语言实现的发生器产生随机数的效率,另一方面是后面的游程检验需要比较大的样本量。Matlab内置的发生器及大部分的函数,底层实现都是 C 或者 Fortran,MathWorks创始人Cleve B. Moler是数值分析领域著名的LINPACK和EISPACK包的作者之一,他当年做了很多优化和封装,进而推出Matlab,只要是调用内置函数,效率不会比C差,自己写的含有循环、判断等语句的

8、代码,性能就因人而异了,对大多数人来说,性能要比C低。这里比较Matlab内置SWB发生器(就当作是C语言实现的好了和用Matlab重写的SWB发生器的效率,代码如下:% matlab codetic % 大约几秒rng(1234, v5uniform) % 调用SWB发生器x = rand(1,224);toc% octave codeid = tic % 时间耗费大约一小时randtx(state,0)x = randtx(1,224);toc (id)randtx不是Matlab和Octave内置的函数,而是Cleve B.Moler基于Matlab实现的SWB发生器,也是100多行包含

9、嵌套循环等语句的Matlab代码打包的函数,上面的代码运行时间差异之大也就不难理解了,为了能在Octave上跑,我做了少量修改,Octave软件版本为4.2.1,安装Octave时,Blas选择OpenBlas,为了后续检验,在获得随机数后,将其保存到磁盘文件random_number.matsave -mat random_number.mat x R,Octave,Matlab和Python内置的发生器都是MT发生器,与之实现有关的数学库,也是Blas,虽然有开源和进一步优化的商业版本之分,但是矩阵乘法,向量乘法之类运算的效率也就半斤八两,Julia语言官网给出了一个标准测试2。不同语言的

10、性能表现(C语言在算法中的表现为基准,时间记为1.0)这里再给出用C语言实现的MT发生器,产生同样多的随机数,只需要10秒左右,其中包含编译和写随机数到文件的时间,实际产生随机数的时间应该远小于这个时间。(程序运行环境环境Dev-C+ 5.11,用64位的GCC编译)。统计检验随机数的检验是有一套标准的,如George Marsaglia开发的DieHard检验程序,检验的内容很丰富。这篇文章只能算初窥门径,R内产生真随机数的包是 Dirk Eddelbuettel 开发的random包,它是连接产生真随机数网站的接口。相关性检验先来一个简单的,就用R产生的两个独立同均匀分布样本,调用cor.

11、test做相关性检验,看看这两组数是不是足够独立同分布,通过眼球验证,随着样本量增大,相关性趋于0,相关性弱到可以视为独立。如下图所示library(ggplot2)library(viridisLite)library(viridis)set.seed(1234)corr - rep(0, 1000) for(i in seq(from = 1000, to = 1000000, by = 1000) corri/1000 - cor.test(runif(i, min = 0, max = 1), runif(i, min = 0, max = 1)$estimate ggplot(dat

12、a.frame(x = seq(1000), y = corr), aes(x = x, y = y) + geom_hex(show.legend = FALSE) + scale_fill_viridis(direction = -1) + xlab(Sample size *103) + ylab(Correlation) 分布检验检验产生的随机数是否服从指定的分布:原假设是样本来自指定的分布,计算的P值比较大,就不能拒绝原假设。ks.test(runif(1000), punif) #分布检验# One-sample Kolmogorov-Smirnov test# data: run

13、if(1000)# D = 0.022302, p-value = 0.7025# alternative hypothesis: two-sided检验两样本是否来自同一分布:原假设是两样本来自同一分布,计算的P值比较小,就表示两样本不是来自同一分布。ks.test(runif(1000), runif(1000) #同分布检验# Two-sample Kolmogorov-Smirnov test# data: runif(1000) and runif(1000)# D = 0.04, p-value = 0.4005# alternative hypothesis: two-sided

14、从结果来看,R内置的随机数发生器通过了检验(嘿嘿,这是肯定的!)。游程检验游程检验对随机数序列的随机性检验,不对序列做任何分布假设,不同于上面的相关性检验和省略没讲的特征统计量(如均值和方差)的检验。先对随机性略作解释,简单起见,我们考虑0-1序列,抛掷均匀的硬币1000次,正面向上记为1,反面向上记为0,这是一个离散的均匀分布,每一次抛掷硬币都无法准确地判断出现的是正面还是反面,若记录的序列中0和1相对集中的出现,不是随机,0和1交替出现,呈现周期性也不是随机,除了这两种情况基本就是随机了。游程检验的原假设是序列满足随机性,序列一旦生成,就是有序的,因为游程检验需要固定位置,再数上升(下降)

15、的游程数,当计算的P值比较大时,不能拒绝原假设,即不能否认这个序列是随机的。对上述0-1序列进行模拟,然后检验,如下所示library(tseries)x - sample(c(0, 1), 1000, replace = TRUE, prob = c(1/2, 1/2)runs.test(factor(x)# Runs Test# data: factor(x)# Standard Normal = 0.45116, p-value = 0.6519# alternative hypothesis: two.sided现在用游程检验比较SWB发生器(Octave/Matlab版)、MT发生器(R语言版)和MT发生器(C语言版)。对于一般的实数序列,得先指定一个阈值,记为delta,然后比较序列中的值和delta的大小关系,这里类似数上升或下降的游程长度(runs length),基于这样一个事实:如果序列表现随机,则序列中两

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 教学/培训

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号