Loren在Matlab的艺术上

将想法转化为matlab

具有随机数的新方法,第一部分

今天我想介绍一位客人博客,彼得珀金斯,他是Mathworks的统计软件开发人员。在他的生命中,他在Mathworks之前,他作为一个统计学家为美国国家海洋渔业服务进行海洋哺乳动物研究,他在Matlab的兴趣之一是随机数生成和蒙特卡罗模拟。

内容

几乎所有使用matlab的人都使用过兰特要么兰德在一次或另一个时功能。然而,人们使用它们的方式广泛变化。有时,您可能只想填写包含0或1以外的值的向量或矩阵,以便尝试您写入的一些新的代码行。在频谱的另一端,您可能正在运行Monte-Carlo仿真,其中伪随机值的统计特性物质。

但是,无论上下文如何,我一直听到的一个问题是,我如何以及何时应该初始化或重新初始化或重置MATLAB的随机数生成器?“我通常给予的答案是,恼火,另一个问题:“你为什么要这样做?”这是因为随机数生成器的状态可能会影响它生成的值的统计属性,并且正确答案到原始问题取决于上下文 - 通常,答案是“别”的答案。有很多可能会说什么时候为什么,我会触摸它。但大多数情况下,我想展示一些如何这是Matlab R2008B的新功能。

如果要运行我用于创建此博客条目的代码,则需要R2008B或更高版本,并且您将希望从新鲜的MATLAB会话开始,或者执行这两个命令(别担心,我'll解释他们的工作。

mtstream = randstream('mt19937ar');randstream.setDefaultStream(MTStream);

Matlab中的随机流

Matlab R2008B中的新增是添加随机数流。随机数流只是它听起来的声音:一个随机值序列的源。通常,人们谈论标准均匀分布的值流,这也是Matlab使用的感觉。实际上,Matlab始终在抽象中有随机数流,下面兰特兰德。但在R2008B中,Streams是您可以直接互动的东西,您甚至可以创建自己的流。有很多谈论那里,但这篇文章是关于如何初始化或重置流,所以以下是一个简短的摘要。有更多在Matlab的文件中。

经常,你根本不需要担心溪流;Matlab在启动时为您创建一个。兰特兰德和新的兰迪函数绘制该流的值,您可以在不知道或关心他们来自的流程的情况下生成随机数。这没有错了 - 如果Matlab中的随机数生成器正常执行工作(并且在R2008B中,您可以选择三个基于最先进的算法的发电机,您应该只生成随机数使用兰特兰德要么兰迪,并处理它们作为独立随机值返回的所有内容。

但是如何回复并重现您生成的随机值或以其他方式控制它们的生成方式?有一种新的方法来做这一点:你在matlab中与一个新的对象交互,一个代表随机流。让我们获取MATLAB在启动时创建的流。

defaultstream = randstream.getdefaultStream()
DefaultStream = MT19937AR随机流(当前默认)种子:0 Rangnalg:Ziggurat

“MT19937AR”表示此流使用最常见的流来生成值Mersenne Twister算法,所在的相同算法兰特几个版本。还有其他发电机选择;更多关于这一刻。Matlab使用0的种子创建了流的流;更多关于在一瞬间。

什么是兰诺格?R2008B中有一个新的事情是兰德从相同的流中绘制值兰特,尽管当然必须将均匀的值转化为标准正态分布。这里所示的流使得使用该转换Ziggurat.算法,虽然你可以改变它(对不起,不再是那个;你必须阅读doc.)。

最后,为此流的显示屏显示它是默认流。这只是意味着它是流的兰特兰德, 和兰迪绘制他们的价值。下面,我将展示如何创建自己的流,并制作默认值。有几个原因可能要这样做。但首先,让我们看看如何使用默认流重现结果。

重置随机流

有时能够从MATLAB的随机数发生器再现输出是有用的。例如,您可能希望重复重新运行Monte-Carlo模拟,使用完全相同的随机值,因为您正在调试代码。实际上,MATLAB每次启动时都会将默认随机流初始化到相同的内部状态,因此同样的调用兰特兰德, 和兰迪将每次启动MATLAB返回相同的“随机”值(除非您采取级别 - 在一分钟内更多地)。但每次想要重新运行模拟时,必须重新启动matlab会令人疑惑。

再现随机数发生器输出的最简单方法是重置默认流,该流将该流放回最初创建时它的状态。

重置(DefaultStream)Z1 = RANDN(1,5)
Z1 = 0.53767 1.8339 -2.2588 0.86217 0.31877

如果我再做一次,我会再次获得相同的值。

重置(DefaultStream)Z2 = RANDN(1,5)
Z2 = 0.53767 1.8339 -2.2588 0.86217 0.31877

虽然简单,重置是一种钝的乐器,只能在非常庞大的规模上提供再现性 - 就好像你重启matlab。除非您真的想重复使用相同的随机序列,否则这不是您应该做的。

播种流

所有伪随机数发生器都有种子的概念。将流作为非常长的值序列,包裹成圆圈,因为它在疲惫时重复。将种子视为您在创建流时指定的圆圈上的起始位置。(通常)(通常)比有种子的多个随机值,所以无法通过指定种子来开始任何地方。并且通常没有简单的描述,例如,除了知道它们代表不同的起始位置之外的种子1或2,种子1或2呈现。但是,如果您创建具有相同种子的流,则每次都会获得相同的值序列。

当MATLAB开始时,它会创建具有相当于的命令的默认流

Stream0 = RANDSTREAM('mt19937ar''种子',0)randstream.setdefaultstream(Stream0);
Stream0 = MT19937AR随机流种子:0 Rangnalg:Ziggurat

我们早先看到了。如果我创建一个具有不同种子的新流,例如

Stream1 = RANDSTREAM('mt19937ar''种子'1)
Stream1 = MT19937AR随机流种子:1 Rangnalg:Ziggurat

和做默认流,

randstream.setDefaultStream(Stream1);

我会得到一个不同的随机值的序列。

Randn(1,5)
ANS = -0.64901 1.1812 -0.75845 -1.1096 -0.84555

但如果我总是使用相同的种子,我将始终获得相同的随机数流。这是重置当前默认流的很多 - 实际上,重置只不过是重新预定。我如何使用的主要区别重置在这里,这里,我创建了自己的流,所以我知道确切地我得到了什么。之前,我会得到重复性,但具体的随机值取决于当前默认流下面的发生器算法。

重新预期是一种大锤子 - 每次需要一组随机值时都不想要创建新的流。如果您将其用作初始化步骤,可能在Matlab Startup中可能在运行模拟之前,这是最有用的。

使用子流进行再现性

我们已经看到了一种使用的缺点重置要么'种子'重现结果是你基本上必须从一开始就开始。R2008B,SubStreams中的一个新功能提供了围绕该缺点的新方法。

还记得圈子吗?由于随机数流中的子流不仅仅是固定的“检查点”,而是由圆周周围的位置定义,以非常大的间隔间隔开。Substreams本身以1开始索引,您可以通过设置流跳转到子流的开头底层财产。从不同的子流生成的值在与流中的连续值相同的感觉中统计上独立。

R2008B支持子流中的两个新的发电机算法:组合多个递归(金宝app'MRG32K3A')乘法滞后的斐波纳契('mlfg6331_64')发电机(Doc有参考)。我会创建一个前一个,并使其成为默认流。

Stream = RANDSTREAM('MRG32K3A');randstream.setDefaultStream(Stream);

要将流重新定位到特定子流的开头,我只是设置了它底层财产。

Stream.substream = 2;

诸如种子,亚体系的比例只不过是沿着一系列随机值的特定点的别名。那么他们有什么不同?我下次进入一些差异,但现在,最明显的区别是您可以在子流之间跳跃而无需创建新的流。这是一个相当轻的操作。

让我们看看如果我将随机数流放到循环的每次迭代之前将随机数流定位到子流的开头。

为了i = 1:5 stream.substream = i;z = rand(1,i)结尾
Z = 0.72701 Z = 0.5582 0.85273 Z = 0.16662 0.29236 0.77278 Z = 0.34773 0.38864 0.80161 0.95025 Z = 0.56709 0.68377 0.29879 0.59318 0.69247

现在我可以通过将流重新定位到对应的子流来重现第3次迭代的结果。我没有重新运行整个循环,我甚至开始事先知道我想看看这个迭代。

我= 3;stream.substream = i;z = rand(1,i)
Z = 0.16662 0.29236 0.77278

如果该循环是耗时的蒙特卡罗模拟,那么能够重新创建并调查任何特定的迭代,这将是一个真正的播出,而不会重新统治整个事情。

请记住,您不需要过度使用过量的子流。他们可以使用,在移动到下一个位置之前,你不必担心每个子流中的所有值,但是每次跳到另一个极端并跳到不同的子流都会毫无意义您生成一个新值。Substreams不添加随机性,它们只是使其更容易再现值。

保存和恢复状态

兰特兰德伪随机数发电机,所有伪随机生成器算法都有一个内部状态,确定下一个值是什么。这是一种确定性算法。还记得圈子吗?沿圆圈的每个点对应于不同的状态。但对于几乎所有现代算法,该状态比仅生成的最后一个数字或流中当前位置的简单索引更复杂。

让我们获取默认生成器的状态。要这样做,我会读的状态财产。

defaultstream = randstream.getdefaultstream()savedstate = defaultstream.state;谁是救世者
DefaultStream = MRG32K3A随机流(当前默认)种子:0 Rangnalg:Ziggurat名称大小字节类别属性SavedState 12x1 48 UInt32

如果我打电话兰特生成几个随机值,

U1 =兰特(1,5)
U1 = 0.83911 0.51069 0.84469 0.68938 0.23777

然后我恢复我保存的状态,

defaultstream.state = savedstate;

兰特下次我调用它时会生成完全相同的值。

U2 =兰特(1,5)
U2 = 0.83911 0.51069 0.84469 0.68938 0.23777

这也是如此兰德而对于兰迪。并且因为所有三个函数从相同的默认流绘制值,只有一个状态才能担心 - 默认流的状态。我可以使用先前保存的状态来重现结果兰德, 例如。

defaultstream.state = savedstate;z1 = randn(1,5)
Z1 = 0.048564 0.87031 0.52365 0.095609 -0.79233
defaultstream.state = savedstate;z2 = randn(1,5)
Z2 = 0.048564 0.87031 0.095609 -0.79233

重要的是要记住,因为有一个单个默认流,调用一个函数会影响其他返回的特定值。

savedstate = defaultstream.state;U1 = RAND(1,5)U2 = RAND(1,5)
U1 = 0.045212 0.48758 0.75138 0.36639 0.5676 U2 = 0.10969 0.27046 0.10359 0.87516 0.28295
defaultstream.state = savedstate;%这返回与以前相同的向量U1 =兰特(1,5)%呼叫randn在两个电话之间的兰德之间z = randn(1,5);%这返回比以前不同的值U2 =兰特(1,5)
U1 = 0.045212 0.48758 0.75138 0.36639 0.5676 0.5676 U2 = 0.20425 0.043083 0.54273 0.10648 0.20139

函数不与它们返回的值独立行动,但是,三个函数生成的值仍然可以被视为统计上无论您生成哪些顺序,都独立。

保存和恢复状态的一个实际应用可能是通过在运行之前保存状态来重现整个Monte-Carlo仿真运行。另一个可能是在蒙特卡罗模拟中重新创建一个特别有趣的迭代,在迭代之前保存了状态。另一个可能是重新创建一次电话兰特在您的代码中发生深,因此您可以在其他地方进行调用,也许是为了调试。只要您在适当的点挽救了国家,您可以“跳转到”任何地方在随机值的序列中。这是在重置或播种流的优势,但它也是抓住:你必须事先节省正确的国家。

除了旁边,Matlab中可用的各种发电机的内部状态都有不同的尺寸和格式,您可以通过查看它们是什么状态不同流的财产。但我建议不要太熟悉,或修改这些国家向量的内部工作。读'n'写'他们,是的,也许甚至是绳子'n'牌子的em,但不要试图理解他们。

哪里不做任何这一点

有时,自行决定是更好的勇气部分。小心了解为什么和你这样做的时候。请记住,重置或替换默认流,或写入其状态,或跳转到子流影响到所有后续调用兰特兰德, 和兰迪,并且可能不是您想要深入的代码深处的东西 - 太容易忘记它在那里。替换默认流,尤其是您需要做很多的东西。

下次

我们已经看到了四种方法来重现Matlab的随机数发生器的结果。

  • 重置流
  • 用固定种子创建新的流
  • 底线
  • 显式保存和恢复发电机状态

但有时需要什么是“再现性相反” - 您希望确保不同的仿真使用运行不同的随机输入,因为您希望能够假设不同的运行是统计上独立的。直到下次 ...

其他情况?

您能想到任何您需要重现无法通过我所显示的示例处理的随机数的情况吗?让我知道这里




发布MATLAB®7.7

|

评论

要发表评论,请点击这里登录您的MathWorks帐户或创建新的。