加载一些包会影响随机数生成吗?

Fra*_*KKK 3 r tmap r-sf

我发现加载一些包会影响R中的随机数生成,问题可以复现如下。

(1) 打开一个新的 R 会话。(我的情况:R 4.x + RStudio)

(2) 执行以下代码:

set.seed(1)
library(sf)
library(tmap)
sample(1:10, 5)
Run Code Online (Sandbox Code Playgroud)

(3) 第一次的结果是:5 10 2 8 6

(4) 但是,如果多次执行整个代码,结果(第一次之后)总是: 9 4 7 1 2

为什么第一次的结果不一样?看来第一次加载sf和tmap库会影响随机数的生成。这么奇怪。

Ben*_*ker 5

一些实验表明问题出在tmap包上,而不是sf(即从一个干净的 R 会话中,set.seed(1); library(sf); sample(1:10, 5)9 4 7 1 2.

如果我们转到它的 GitHub 存储库,我们可以看到 tmap 包有一个.onLoad函数(这里),它将在第一次加载包时运行(从技术上讲,library(tmap)第二次调用不会加载包,因为它已经加载了...)

再深入一点,我们可以诊断出这些问题

set.seed(1)
r <- .Random.seed
f <- function() identical(r, .Random.seed)
Run Code Online (Sandbox Code Playgroud)

然后f()在每一步之后检查;TRUE 除非随机数流已被更改,否则它将是。我在这个答案中使用了这种方法......

这很难弄清楚,因为几乎不可能.onLoad执行所有函数(例如,如果您调用tmap:::working_internet(),则首先加载包以访问该函数),并且设置一个并不容易(不可能?).onLoad函数本身的调试标志(因为在加载包之前无法访问它)。

我最初被误导相信它是导致问题的间接加载的其他包之一tmapnames(sessionInfo()$loadedOnly)显示有 52 个!)。追踪这将是一个巨大的痛苦。我可能会尝试通过消除来做到这一点,采用这些包的名称并排除任何加载的 (eg) sfor tidyverse,这两个都不会显示这个问题。然而,事实证明这没有必要。

在放屁之后(R -d gdb在内部unif_randC 函数上使用并设置断点),我意识到它sample()被调用了,然后sample()determine_tips_order这里)中使用了一个随机化步骤 via ,它从.onLoad. 这用于设置向用户提供有关 tmap 的随机“提示”的顺序——在我看来,这真的应该在第一次tmap_tip()被调用时被调用,而不是在包加载时......(你可以提出包的 github repo 上的问题...)

(如果可以的话,我实际上会使其成为 CRAN 存储库策略,使包加载不会以这种方式与随机数流混淆......)