3

我担心将来正在运行的代码可能会失败。我已经看到tidyverse运行良好但一段时间后返回错误的函数,因为它们已经失效了。要给出一些可重现的示例,请尝试如何制作一个伟大的 R 可重现示例中的这段代码,具有讽刺意味的是,它不再可重现(比较原始帖子的值agex与原始帖子的值):

set.seed(42)  ## for sake of reproducibility
n <- 6
dat <- data.frame(id=1:n, 
                  date=seq.Date(as.Date("2020-12-26"), as.Date("2020-12-31"), "day"),
                  group=rep(LETTERS[1:2], n/2),
                  age=sample(18:30, n, replace=TRUE),
                  type=factor(paste("type", 1:n)),
                  x=rnorm(n))
dat
  id       date group age   type           x
1  1 2020-12-26     A  29 type 1  0.63286260
2  2 2020-12-27     B  30 type 2  0.40426832
3  3 2020-12-28     A  21 type 3 -0.10612452
4  4 2020-12-29     B  28 type 4  1.51152200
5  5 2020-12-30     A  26 type 5 -0.09465904
6  6 2020-12-31     B  24 type 6  2.01842371

问题

是否只有在更新相同的代码返回不同输出的情况下?换句话说:包及其R本身通常不会自动更新,这是否意味着只要我不手动更新任何东西,我就可以重新运行一个“永恒”的功能?有什么例外吗?

为什么我问

bcrypt使用R. 我们需要加密数据删除原始数据。一旦完成,就没有回头路了,即我真的必须相信代码。我不使用 pacakges 但bcrypt,shinyshinydashboard.

编辑

我的问题假设代码在同一系统上运行而不更改全局设置(在@qdread 的评论后编辑)而不更改 R 版本。

我的工作细节:我处理患者数据。首先,我为每位患者选择一个由字母和数字组成的随机 ID,A72CV例如Max Cooper 1987-05-03. 在下一步中,我使用bcrypt为每个患者创建盐,然后使用盐创建 ID 的散列/加密版本(盐 + ID = 加密 ID)。因此,每个患者都有姓名 + 出生日期、随机字母/数字 ID、盐(使用 生成salt <- bcrypt::gensalt(log_rounds = 12))和加密 ID(使用生成id_encrypted <- bcrypt::hashpw(id, salt = salt))。我将数据保存在三个单独的文件中:(i) 患者数据,即姓名和出生日期,以及加密的 ID,(ii) ID 和盐以及 (iii) 带有 ID 和一些感兴趣的变量的实际数据库,例如吸烟者/重量,... 这种方法是在我工作的环境中被一些机构推荐的,它被称为假名化(一种可逆加密)。它确保即使存在数据泄漏,识别变量名称 + 生日与所有感兴趣的变量(吸烟者,...)之间也没有明显的联系。我制作了一个 ShinyApp,允许我的同事(1)提供 ID 并查找姓名 + 出生日期,(2)提供姓名 + 出生日期并查找 ID,以及(3)为新患者生成一个 ID。这一切都有效,因为具有相同盐的相同 ID 会产生相同的加密(散列)ID - 至少现在是这种情况。但是,如果将来由于某些原因,相同的输入(例如 ID)不会返回相同的输出(例如姓名 + 生日),那我就完蛋了。另一方面,如果随机ID的生成会随着时间而改变,这不是一个大问题,因为每个ID只被创建和保存一次,即这个过程不必是可重现的。所描述的加密方法将应用于我的机构多年收集的一些数据库。如果我们不能重新创建数据,一切都会丢失。这就是为什么代码稳定性对我如此重要的原因。我会在同事的windows电脑上安装shinyApp。他们只会打 如果随机 ID 的生成会随着时间而改变,这不是一个大问题,因为每个 ID 只创建和保存一次,即这个过程不必是可重现的。所描述的加密方法将应用于我的机构多年收集的一些数据库。如果我们不能重新创建数据,一切都会丢失。这就是为什么代码稳定性对我如此重要的原因。我会在同事的windows电脑上安装shinyApp。他们只会打 如果随机 ID 的生成会随着时间而改变,这不是一个大问题,因为每个 ID 只创建和保存一次,即这个过程不必是可重现的。所描述的加密方法将应用于我的机构多年收集的一些数据库。如果我们不能重新创建数据,一切都会丢失。这就是为什么代码稳定性对我如此重要的原因。我会在同事的windows电脑上安装shinyApp。他们只会打run AppR然后执行前面描述的选项之一(1 到 3)。

4

1 回答 1

4

(部分回答。)

sample在 R-3.6.0中更改了默认行为。值得注意的是,在R-3.6.0 下的NEWS-3中,它在SIGNIFICANT USER-VISIBLE CHANGES下声明:

从离散均匀分布生成的默认方法(sample()例如,在 中使用)已更改。这解决了 Ottoboni 和 Stark 指出的事实,即先前的方法sample()在大量人群中明显不均匀。有关讨论,请参阅PR#17494。以前的方法可以使用RNGkind()RNGversion()如果需要复制旧结果来请求。感谢 Duncan Murdoch 贡献补丁和 Gabe Becker 进一步帮助。

我们可以age通过改变sample.kind="Rounding",重新获得随机值

RNGkind(sample.kind = "Rounding")
# Warning in RNGkind(sample.kind = "Rounding") :
#   non-uniform 'Rounding' sampler used

set.seed(42)  ## for sake of reproducibility
n <- 6
dat <- data.frame(id=1:n, 
                  date=seq.Date(as.Date("2020-12-26"), as.Date("2020-12-31"), "day"),
                  group=rep(LETTERS[1:2], n/2),
                  age=sample(18:30, n, replace=TRUE),
                  type=factor(paste("type", 1:n)),
                  x=rnorm(n))
dat
#   id       date group age   type           x
# 1  1 2020-12-26     A  29 type 1  0.63286260
# 2  2 2020-12-27     B  30 type 2  0.40426832
# 3  3 2020-12-28     A  21 type 3 -0.10612452
# 4  4 2020-12-29     B  28 type 4  1.51152200
# 5  5 2020-12-30     A  26 type 5 -0.09465904
# 6  6 2020-12-31     B  24 type 6  2.01842371

至于更改后的rnorm输出,在同一链接中指出

注意:set.seed()R >3.6.0 和以前的版本之间的输出不同。指定您用于随机过程的 R 版本,如果您在回答旧问题时得到的结果略有不同,请不要感到惊讶。要在这种情况下获得相同的结果,您可以RNGversion()在 set.seed() 之前使用 -function(例如:)RNGversion("3.5.2")

不幸的是,我无法重现x-column 的链接版本。


在生产中如何处理?在单元测试中依赖真正的随机数总是粗略的(出于诸如此类的原因),主要有两个原因:您不能总是假设未播种的随机值会遇到您想要的极端情况;正如您在此处看到的,种子随机值受“错误修复”或 PRNG 流程改进的影响。

于 2022-02-15T14:42:00.813 回答