问题描述
(1) 打开一个新的 R 会话。 (我的情况:R 4.x + RStudio)
(2) 执行如下代码:
set.seed(1)
library(sf)
library(tmap)
sample(1:10,5)
(3) 第一次的结果是: 5 10 2 8 6
(4) 但是,如果多次执行整个代码,结果(第一次之后)总是: 9 4 7 1 2
为什么第一次的结果不一样?看来第一次加载sf和tmap库会影响随机数的生成。好奇怪。
解决方法
一点点实验表明问题出在 tmap
包上,而不是 sf
(即从一个干净的 R 会话中,set.seed(1); library(sf); sample(1:10,5)
给出了 9 4 7 1 2
。>
如果我们访问它的 GitHub 存储库,我们可以看到 tmap 包有一个 .onLoad
函数(here),它将在第一次加载包时运行(技术上,调用 {{ 1}} 第二次不加载包,因为它已经加载了...)
深入一点,我们可以诊断出这些问题
library(tmap)
然后在每一步后检查set.seed(1)
r <- .Random.seed
f <- function() identical(r,.Random.seed)
;它将是 f()
除非随机数流已被更改。
我在 this answer ...
这很难弄清楚,因为几乎不可能不执行所有 TRUE
函数(例如,如果您调用 .onLoad
,首先 加载包以访问该函数),并且在 tmap:::working_internet()
函数本身上设置调试标志并不容易(不可能?)(因为在加载包之前无法访问它)。
我最初被误导,认为是由 .onLoad
间接加载的other 包之一导致了问题(tmap
显示其中有 52 个!)。追踪这将是一个巨大的痛苦。我可能会尝试通过消除来做到这一点,采用这些包的名称并排除任何加载的(例如)names(sessionInfo()$loadedOnly)
或 sf
,这两个都没有显示此问题。然而,事实证明这没有必要。
在放屁之后(使用 tidyverse
并在内部 R -d gdb
C 函数上设置断点),我意识到 unif_rand
被调用,然后通过 { 进行随机化步骤{1}} 正用于从 sample()
调用的 sample()
(here)。这用于设置向用户提供有关 tmap 的随机“提示”的顺序 - 在我看来,这确实应该在第一次调用 determine_tips_order
时调用,而不是在包加载时调用。 .(你可以在包的 github repo 上提出问题......)
(如果可以的话,我实际上会使其成为 CRAN 存储库策略,包加载不会以这种方式与随机数流混淆...)