【问题标题】:Loading some packages affects random number generation?加载某些包会影响随机数生成?
【发布时间】:2021-09-10 04:55:57
【问题描述】:

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

(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 库会影响随机数的生成。好奇怪。

【问题讨论】:

    标签: r sf tmap


    【解决方案1】:

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

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

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

    set.seed(1)
    r <- .Random.seed
    f <- function() identical(r, .Random.seed)
    

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

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

    我最初被误导认为是由tmap 间接加载的other 包之一导致了问题(names(sessionInfo()$loadedOnly) 显示其中有 52 个!)。追踪这将是一个巨大的痛苦。我可能会尝试通过消除来做到这一点,取这些包的名称并排除任何由(例如)sftidyverse 加载的内容,它们都没有显示这个问题。然而,事实证明这是没有必要的。

    经过一番放屁(使用R -d gdb 并在内部unif_rand C 函数上设置断点),我意识到sample() 正在被调用,因此通过sample() 的随机化步骤被用于determine_tips_orderhere),从.onLoad调用。这用于设置向用户提供关于 tmap 的随机“提示”的顺序——在我看来,这确实应该在第一次调用 tmap_tip() 时调用,而不是在加载包时调用......(你可以在包的 github repo 上提出问题...)

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

    【讨论】:

    • 非常感谢您的回答。希望 tmap(和其他包)不会弄乱随机数流。
    • 一旦你知道它,解决它并不太难......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-27
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    相关资源
    最近更新 更多