_targets.R函数能够从targets列表中读取对象吗?

huangapple go评论77阅读模式
英文:

Can function of _targets.R read object from targets list?

问题

问题

r中使用targets包,我们在_targets.R文件中创建函数和targets对象。在一个函数中,我想根据全局环境中的对象来计算,而不仅仅是基于输入对象。然而,似乎这种方式不起作用。

我所做的

我将提供两个示例,展示了我们如何在不使用和使用targets包的情况下编写代码。第一个示例运行正常,但第二个代码由于我上面提到的问题而无法工作。

第一个示例。让我们从一个空的项目文件夹开始。我创建一个新的R脚本,这是我们通常在不使用targets包的情况下进行的方式。

# 一个用于对两个值求和然后减去1的函数
fun_sum_1 <- function(x, y) {
  res <- sum(x, y) - 1
  return(res)
}
my_x <- 2
my_y <- 3
my_res <- fun_sum_1(my_x, my_y)
my_res
# [1] 4

然后,我几乎使用相同的方式使用targets包。首先,创建一个新的R脚本并命名为“_targets.R”。在这个_targets.R中写入以下代码并保存文件。

library(targets)

# 一个用于对两个值求和然后减去1的函数
fun_sum_1 <- function(x, y) {
  res <- sum(x, y) - 1
  return(res)
}

# targets列表
list(
  tar_target(my_x, 2), 
  tar_target(my_y, 3), 
  tar_target(my_res, fun_sum_2(my_x, my_y))
)

然后,我们在控制台面板中运行_targets.R中的以下代码。

library(targets)
tar_make()

您将看到运行的进度。与上面的常规做法的不同之处在于在环境面板中没有出现“my_x”或“my_y”或“my_res”或“fun_sum_1”。然后,我们通过在控制台面板中运行以下代码来加载结果到全局环境中。

tar_load(my_res)
my_res
# [1] 4

如果运行tar_visnetwork(),我们可以看到目标对象的流程图。

然后我们进入第二个示例,存在问题的示例。首先,我们像往常一样编写代码。

# 首先清空全局环境
rm(list = ls())

# 一个用于对两个值求和和全局环境中的一个现有值再减去1的函数
# 它不同于fun_sum_2,因为它不仅依赖于输入对象
# 还依赖于全局环境中的“my_z”
fun_sum_2 <- function(x, y) {
  res <- sum(x, y, my_z) - 1
  return(res)
}
my_x <- 2
my_y <- 3
my_z <- 4
my_res <- fun_sum_2(my_x, my_y)
my_res
# [1] 8

现在,我们尝试使用targets包来制作这个示例。我们将_targets.R修改为以下代码并保存文件。

library(targets)

# 一个用于对两个值求和然后减去1的函数
fun_sum_2 <- function(x, y) {
  res <- sum(x, y, my_z) - 1
  return(res)
}

# targets列表
list(
  tar_target(my_x, 2), 
  tar_target(my_y, 3), 
  tar_target(my_z, 4), 
  tar_target(my_res, fun_sum_2(my_x, my_y))
)

然后,我们在控制台面板中运行以下代码。但是会发生错误。

library(targets)
tar_make()
# ✔ skip target my_x
# ✔ skip target my_y
# ✔ skip target my_z
# • start target my_res
# ✖ error target my_res
# • end pipeline [0.095 seconds]
# Error:
#   ! Error running targets::tar_make()
# Error messages: targets::tar_meta(fields = error, complete_only = TRUE)
# Debugging guide: https://books.ropensci.org/targets/debugging.html
# How to ask for help: https://books.ropensci.org/targets/help.html
# Last error: object &#39;my_z&#39; not found

尽管我在目标列表中创建了my_z,但似乎fun_sum_2无法读取它。当然,我可以将my_z作为fun_sum_2函数的一个输入来解决这个问题。但是,如果我有一个依赖于全局环境中许多对象的函数呢?

我想知道如何在不将my_z作为fun_sum_2函数的输入之一的情况下解决这个问题。

英文:

Problem

Using targets package in r, we make functions and targets obejcts in _targets.R file. In a function, I want to calculate something not just based on the input obejects but also based on the objects in the global environment. However, seems that it doesn't work in this way.

What I have done

I will give two example, showing how we write code without and with targets package. The first one runs without problem, but the second code doesn't work due to the problem I mentioned above.

The first example. Let's start from a empty project folder. I make a new R script, and this is how we do generally without using targets package.

# a function to sum 2 values then minus 1
fun_sum_1 &lt;- function(x, y) {
  res &lt;- sum(x, y) - 1
  return(res)
}
my_x &lt;- 2
my_y &lt;- 3
my_res &lt;- fun_sum_1(my_x, my_y)
my_res
# [1] 4

Then I do almost the same thing using targets package. Firstly, make a new R script and name it "_targets.R". Write the following code in this _targets.R and save the file.

library(targets)

# a function to sum 2 values then minus 1
fun_sum_1 &lt;- function(x, y) {
  res &lt;- sum(x, y) - 1
  return(res)
}

# targets list
list(
  tar_target(my_x, 2), 
  tar_target(my_y, 3), 
  tar_target(my_res, fun_sum_2(my_x, my_y))
)

Then we run the _targets.R in console pannel with the following code.

library(targets)
tar_make()

You will see the progress of the runing. The difference between this and general practice above is that there is not "my_x" or "my_y" or "my_res" or "fun_sum_1" showing up in the environment pannel. Then we load the results to our global environment by runing the following code in the console pannel.

tar_load(my_res)
my_res
# [1] 4

And if we run tar_visnetwork(), we can see a flowchart of the target obejcts.

Then we go to the second example, the example with problem. First, we write code as usual.

# clean the global environment first
rm(list = ls())

# a function to sum 2 values and 1 existing value of global environment then minus 1
# it differs from fun_sum_2 that it doesn&#39;t only rely on input obejects
# but also the &quot;my_z&quot; in the global environment
fun_sum_2 &lt;- function(x, y) {
  res &lt;- sum(x, y, my_z) - 1
  return(res)
}
my_x &lt;- 2
my_y &lt;- 3
my_z &lt;- 4
my_res &lt;- fun_sum_2(my_x, my_y)
my_res
# [1] 8

Now we try to make this using targets package. We revise the _targets.R into the code below, and save the file.

library(targets)

# a function to sum 2 values then minus 1
fun_sum_2 &lt;- function(x, y) {
  res &lt;- sum(x, y, my_z) - 1
  return(res)
}

# targets list
list(
  tar_target(my_x, 2), 
  tar_target(my_y, 3), 
  tar_target(my_z, 4), 
  tar_target(my_res, fun_sum_2(my_x, my_y))
)

Then we run the following code in console pannel. But then error happens.

library(targets)
tar_make()
# ✔ skip target my_x
# ✔ skip target my_y
# ✔ skip target my_z
# • start target my_res
# ✖ error target my_res
# • end pipeline [0.095 seconds]
# Error:
#   ! Error running targets::tar_make()
# Error messages: targets::tar_meta(fields = error, complete_only = TRUE)
# Debugging guide: https://books.ropensci.org/targets/debugging.html
# How to ask for help: https://books.ropensci.org/targets/help.html
# Last error: object &#39;my_z&#39; not found

Though I make a my_z in the targets list, but seems that fun_sum_2 can't read it. Of course, I can make my_z an input into the fun_sum_2 function, which will solve the problem. However, what if I have a function relying on many objects in the global environment?

I wonder how can I solve this problem without making my_z one of the inputs for the fun_sum_2 function.

答案1

得分: 1

这与函数作用域或环境有关。你应该知道你的函数 fun_sum_2() 是在全局环境中定义的,在其中你找不到一个名为 my_z 的对象。要使其工作,你应该将 my_z 的定义也移到全局块中。以下代码应该可以工作:

targets::tar_dir({
  targets::tar_script({
    library(targets)
    
    # 一个用于求和两个值然后减去1的函数
    fun_sum_2 <- function(x, y) {
      res <- sum(x, y, my_z) - 1
      return(res)
    }
    my_z <- 4
    
    # 目标列表
    list(
      tar_target(my_x, 2), 
      tar_target(my_y, 3), 
      tar_target(my_res, fun_sum_2(my_x, my_y))
    )
  })
  targets::tar_make()
})
#> ▶ 开始目标 my_x
#> ● 构建目标 my_x [0 秒]
#> ▶ 开始目标 my_y
#> ● 构建目标 my_y [0.015 秒]
#> ▶ 开始目标 my_res
#> ● 构建目标 my_res [0 秒]
#> ▶ 结束管道 [0.062 秒]

创建于 2023-07-11,使用 reprex v2.0.2

要了解更多关于环境的信息,你可以阅读Hadley撰写的书中的这一部分

英文:

This is related to function scope or environment. You should know that your function fun_sum_2() is defined in the global environment, within which you cannot find an object named my_z. To make it work, you should move your definition of my_z to the global blocks, too. The following codes should work:

targets::tar_dir({
  targets::tar_script({
    library(targets)
    
    # a function to sum 2 values then minus 1
    fun_sum_2 &lt;- function(x, y) {
      res &lt;- sum(x, y, my_z) - 1
      return(res)
    }
    my_z &lt;- 4
    
    # targets list
    list(
      tar_target(my_x, 2), 
      tar_target(my_y, 3), 
      tar_target(my_res, fun_sum_2(my_x, my_y))
    )
  })
  targets::tar_make()
})
#&gt; ▶ start target my_x
#&gt; ● built target my_x [0 seconds]
#&gt; ▶ start target my_y
#&gt; ● built target my_y [0.015 seconds]
#&gt; ▶ start target my_res
#&gt; ● built target my_res [0 seconds]
#&gt; ▶ end pipeline [0.062 seconds]

<sup>Created on 2023-07-11 with reprex v2.0.2</sup>

For more about environment, you can read this part of the book written by Hadley.

huangapple
  • 本文由 发表于 2023年6月19日 14:11:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76504013.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定