如何解决包环境在管道中未按预期工作
在我正在处理的包中,我使用环境来保存和检索数据帧的标签。
在 magrittr
管道中,我想将它们保存在稍后检索的环境变量中。
但是,我面临一个问题:似乎直到管道结束时环境变量才被修改。
这是一个例子,包含大部分有用的功能:
devtools::install_github("DanChaltiel/crosstable",build_vignettes=TRUE)
library(crosstable) #for functions set_label() and get_label() but you can test
#with other label-management packages (Hmisc,expss...)
labels_env = rlang::new_environment()
save_labels = function(.tbl){
labels_env$last_save = tibble(
name=names(.tbl),label=get_label(.tbl)[.data$name]
)
invisible(.tbl)
}
get_last_save = function(){
labels_env$last_save
}
import_labels = function(.tbl){
data_label = get_last_save()
for(i in 1:nrow(data_label)){
name = as.character(data_label[i,name_from])
label = as.character(data_label[i,label_from])
.tbl[name] = set_label(.tbl[name],label)
}
.tbl
}
这完全按预期工作,否则 disp
的标签将是 NULL
:
library(dplyr)
library(crosstable)
save_labels(mtcars2)
mtcars2 %>%
transmute(disp=as.numeric(disp)+1) %>% #removes the label attribute of disp
import_labels() %>% #
crosstable(disp)
#> .id label variable value
#> 1 disp Displacement (cu.in.) Min / Max 72.1 / 473.0
#> 2 disp Displacement (cu.in.) Med [IQR] 197.3 [121.8;327.0]
#> 3 disp Displacement (cu.in.) Mean (std) 231.7 (123.9)
#> 4 disp Displacement (cu.in.) N (NA) 32 (0)
由 reprex package (v0.3.0) 于 2021 年 1 月 26 日创建
但是,save_labels(mtcars2)
会不可见地返回 mtcars2
,因此我希望能够通过管道传输整个序列。不幸的是,这会引发错误:
library(dplyr)
library(crosstable)
mtcars2 %>%
save_labels() %>%
transmute(disp=as.numeric(disp)+1) %>%
import_labels() %>% #
crosstable(disp)
#> Error in .subset2(x,i,exact = exact): attempt to select less than one element in get1index
由 reprex package (v0.3.0) 于 2021 年 1 月 26 日创建
确实,当使用管道时,当我们到达 import_labels()
时还没有设置环境变量。如果我重新运行此代码,它不会抛出任何错误,但会产生误导,因为它会引用 labels_env$last_save
的先前值。
我对管道的理解不够好,无法实现这一点。此外,它似乎特定于包环境,因为我无法在普通的 R 脚本中重现这种行为。
有没有办法在包内使用带有这种环境变量的管道?
解决方法
这实际上是由包 magrittr
(提供管道)从 v1.5 升级到 v2.0 时发生的重大变化造成的。
这已在 the blog 和 on NEWS.md 上进行了解释。
可以在 this GitHub issue 上找到更具体的可重现示例。
在新的 magrittr
版本中,求值顺序发生了变化,因此要以正确的顺序发生副作用,您必须强制求值:
import_labels = function(.tbl){
force(.tbl) #force evaluation
data_label = get_last_save()
for(i in 1:nrow(data_label)){
name = as.character(data_label[i,name_from])
label = as.character(data_label[i,label_from])
.tbl[name] = set_label(.tbl[name],label)
}
.tbl
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。