首页 > 解决方案 > 惰性求值问题 - tibble 中的函数

问题描述

设置

在此示例中,我将使用 tidyverse 中的 tibble() 来存储函数。

假设我有以下小标题(这是不同功能的小标题),

cost.matrix <- tibble(cost = c(function(x){0}, function(x){0}, function(x){NA}, function(x){x^2}, function(x){(3/2)*x},  function(x){x}),
                           flow = c(function(alpha,beta){(1/2)-alpha},function(alpha,beta){(1/2)-beta},  function(alpha,beta){NA}, function(alpha,beta){alpha},  function(alpha,beta){beta},
                                    function(alpha, beta){1-alpha-beta}))

例如,

cost.matrix$cost
# and
cost.matrix$flow

将列出所有功能。

现在我想创建一个新列,它组成流和成本函数,例如,

function(x){x^2}  
# and
function(alpha, beta){1-alpha-beta}
# The new function will be
function(alpha, beta){(1-alpha-beta)^2}

所以要做到这一点,我使用了一个简单的 for 循环(如果有人有更好的建议,请告诉我,在矢量化以下组合函数时遇到了麻烦),并在每一行上使用了这个组合函数:

Composite <- function(f,g) function(...) f(g(...))

所以现在我们的代码如下所示(我们创建一个新列,然后使用 for 循环将相应的元素替换为 cost 和 flow 列中的组合):

data <- cost.matrix %>%
  mutate(cost.flow.comp = cost)
for (i in 1:nrow(data)){
  a <- data$cost[[i]]
  b <- data$flow[[i]]
  want <- Composite(a,b)
  data$cost.flow.comp[[i]] <- want
}

问题

如果我们运行以下代码,我们现在应该得到 25:

data$cost.flow.comp[[4]](5,2)

因为相关的功能是:

function(x){x^2}
# and
function(alpha, beta){alpha}

但我们得到 -6,因为 cost.flow.comp 列中的每个元素实际上都已分配给以下函数的组合:

function(x){x}
function(alpha,beta){1-alpha-beta}

解决方案 我找到了解决这个问题的方法,它是在函数组合后,每次在 for 循环中调用该函数。例如(我们在分配组合后调用 want 函数):

data <- cost.matrix %>%
  mutate(cost.flow.comp = cost)
for (i in 1:nrow(data)){
  a <- data$cost[[i]]
  b <- data$flow[[i]]
  want <- Composite(a,b)
  want(1,1)
  data$cost.flow.comp[[i]] <- want
}

问题

我找不到的是为什么会这样?我假设一个我不理解的范围特征?

只是为了读者的兴趣,这种方法的用例是表示具有流量和成本的网络。并想和他们一起做手术。

标签: r

解决方案


这是惰性评估而不是范围界定的问题。问题是该Composite函数从不评估for g,它只是创建一个将这些名称作为其主体的一部分的函数。在第一次调用之前,它们的值是不固定的。很难弄清楚这些值的实际来源来解释 -6,但解决方法很简单:更改Composite

Composite <- function(f, g) {
  force(f)
  force(g)
  function(...) f(g(...))
}

然后你的原始版本就可以了。

> data <- cost.matrix %>%
+   mutate(cost.flow.comp = cost)
> for (i in 1:nrow(data)){
+   a <- data$cost[[i]]
+   b <- data$flow[[i]]
+   want <- Composite(a,b)
+   data$cost.flow.comp[[i]] <- want
+ }
> data$cost.flow.comp[[4]](5,2)
[1] 25

顺便说一句,我怀疑有一种更实用的方法来创建cost.flow.comp列,但我不知道这些tidyverse东西。我会用它来做mapply,即

data$new.column <- mapply(Composite, data$cost, data$flow)

推荐阅读