targets流程中嵌套Rmd文件的依赖未被识别,如何处理?
问题描述
我搭建了一个targets流程,用于训练多个模型并最终生成一个flexdashboard(或Rmd文件)汇总模型。汇总用的Rmd文件通过tarchetypes::tar_render()纳入流程,自身依赖管理正常,但问题在于该文件通过knitr::knit_expand()引用了单模型汇总的模板Rmd文件,模板里的额外依赖(比如示例中的varimp1和varimp2)没被targets捕获。想知道能不能手动添加这些依赖,或者有没有更优的方法创建这种按模型生成章节的动态Rmd文件。
最小可复现示例(MWE)
以下流程复现了问题:最终输出output.Rmd,为每个模型调用一次template.Rmd。当前依赖关系中,output目标并未依赖varimp1/2,但模板文件实际用到了这两个目标,导致output可能因varimp1/2不存在或过期而无法生成。
_targets.R
library(targets) library(tarchetypes) # 虚拟函数 train_model <- function(id) { return(id) } get_var_imp <- function(mdl, seed) { # seed参数用于轻松更改并使结果失效 set.seed(seed) return(data.frame(x = runif(1), y = runif(1))) } list( tar_target(model1, train_model(id = "model1")), tar_target(model2, train_model(id = "model2")), tar_target(varimp1, get_var_imp(model1, seed = 1)), tar_target(varimp2, get_var_imp(model2, seed = 2)), tar_target(template_file, "template.Rmd", format = "file"), tar_render(output, "output.Rmd") )
output.Rmd
--- title: "Output" output: rmarkdown::html_document --- # 通用章节 ```{R} # 这些依赖可被正常识别 model1 <- tar_read(model1) model2 <- tar_read(model2)
为每个模型创建新章节
models <- c("model1", "model2") NAME_MAP <- c( model1 = "第一个模型", model2 = "第二个模型" ) txt <- sapply(models, \(target_name) knitr::knit_expand(tar_read(template_file)))
r paste(knitr::knit(text = txt), collapse = '\n')
### `template.Rmd` ```r ```{r, echo=FALSE} # 该依赖可被识别,因已在output.Rmd中存在 mdl <- tar_read_raw("{{target_name}}") mdl_name <- NAME_MAP[["{{target_name}}"]] # 该依赖未被识别!================================= vi <- tar_read_raw(gsub("model", "varimp", "{{target_name}}"))
模型
{{target_name}} - r mdl_name 特征重要性如下:
# 或对mdl执行其他操作 vi
生成的文档会为每个模型生成对应章节,展示特征重要性内容。 --- # 解决方案 ### 方法1:手动添加依赖到`tar_render` `tar_render()`支持通过`deps`参数手动指定额外依赖,这样targets就能识别到varimp1/2是output目标的前置依赖。修改`_targets.R`中的`tar_render`部分: ```r tar_render(output, "output.Rmd", deps = c(varimp1, varimp2))
这种方法简单直接,适合依赖数量少且固定的场景。
方法2:显式加载依赖让targets自动识别
在output.Rmd的开头显式加载所有需要的varimp目标,即使代码里没直接用到,targets的静态分析也会捕获这些依赖:
```{r, include=FALSE} # 显式加载依赖,让targets识别 tar_load(varimp1) tar_load(varimp2)
如果模型数量多,可以用循环动态加载: ```r ```{r, include=FALSE} models <- c("model1", "model2") lapply(models, function(m) { tar_load_raw(gsub("model", "varimp", m)) })
### 方法3:使用动态分支+独立渲染章节(更优解) 如果模型数量较多或后续可能扩展,推荐用targets的动态分支功能,先为每个模型生成独立的章节片段,再汇总到最终文档。 #### 修改`_targets.R` ```r library(targets) library(tarchetypes) train_model <- function(id) { return(id) } get_var_imp <- function(mdl, seed) { set.seed(seed) return(data.frame(x = runif(1), y = runif(1))) } # 定义模型列表 tar_target(model_ids, c("model1", "model2")) # 动态分支训练模型 tar_target(model, train_model(id = model_ids), pattern = map(model_ids)) # 动态分支生成特征重要性 tar_target(varimp, get_var_imp(model, seed = model_ids), pattern = map(model, model_ids)) # 动态分支生成单个模型的章节片段 tar_target(model_section, { # 渲染模板生成章节文本 template <- readLines("template.Rmd") txt <- knitr::knit_expand(text = template, target_name = model_ids) knitr::knit(text = txt, quiet = TRUE) }, pattern = map(model_ids, model, varimp), format = "file") # 汇总所有章节生成最终文档 tar_render(output, "output.Rmd", deps = model_section)
修改output.Rmd
--- title: "Output" output: rmarkdown::html_document --- # 通用章节 ```{r} model_ids <- tar_read(model_ids)
为每个模型创建新章节
r paste(sapply(tar_read(model_section), readLines), collapse = '\n')
这种方法的优势是: - targets能自动追踪每个模型及其依赖的varimp,分支间相互独立,更新单个模型时无需重新渲染所有章节 - 代码结构更清晰,扩展性更强,新增模型只需修改`model_ids`即可 --- 内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

