是否可以在数据框中使用在该数据框中定义的变量调用 eval?
Can eval be called within a data frame with variables defined in that data frame?
考虑:
quotes<-alist(x, x+1, x+2)
data.frame(x=c(5, 10, 15), lapply(quotes, eval))
这不起作用,因为 eval
找不到 x
。有没有办法让 eval
识别数据框中定义的变量?我知道我可以将数据框分配给一些变量,然后使用 transform
等函数构建它,但我希望在调用 data.frame
.[=17= 时完成所有这些操作]
对于预期输出的可能版本,我们可以使用:
quotes<-alist(x, x+1, x+2)
x=c(5, 10, 15)
data.frame(x, lapply(quotes, eval))
调试 data.frame(x=c(5, 10, 15), lapply(quotes, eval))
导致:
x <- list(...)
#Error in FUN(X[[i]], ...) : object 'x' not found
这是由于对第二个参数的评估:
lapply(quotes, eval)
#Error in FUN(X[[i]], ...) : object 'x' not found
如果不事先在 environment
.
中定义 x
,这里似乎很难找到解决方法
tibble
允许在定义更多变量时使用之前的变量,因为它依赖于使用 quos(...)
而不是 list(...)
的非标准评估来处理参数:
function (..., .rows = NULL, .name_repair = c("check_unique",
"unique", "universal", "minimal"))
{
xs <- quos(...)
is.null <- map_lgl(xs, quo_is_null)
tibble_quos(xs[!is.null], .rows, .name_repair)
}
与tibble
:
tibble::tibble(x=c(1,2,3), result= sapply(quotes,function(quo) eval(quo)))
# A tibble: 3 x 2
x result[,1] [,2] [,3]
<dbl> <dbl> <dbl> <dbl>
1 1 1 2 3
2 2 2 3 4
3 3 3 4 5
然而,这还不是预期的结果,因为 quotes
需要使用 x
按行处理,例如 mapply
:
tibble::tibble(x=c(1,2,3), result = mapply(function(quo,x) eval(quo),quotes,x))
# A tibble: 3 x 2
x result
<dbl> <dbl>
1 1 1
2 2 3
3 3 5
您是否注意到更简单的调用 data.frame(x, y = x)
也不起作用?
data.frame()
使用标准评估,因此在您的情况下,它们将在全球环境中进行评估。
不过,如果您为引号元素命名,您将能够做到 tibble(x, !!!quotes)
,因为 tibble 的工作方式不同。
从技术上讲,您可能可以接受以下内容,我们通过在全局环境中创建一个临时值来作弊,然后在退出时将其删除。
(我用evalq
只是为了能用on.exit
)
quotes<-alist(x, x+1, x+2)
df <- data.frame(
x = c(5, 10, 15) ->> .t.e.m.p.,
evalq({
on.exit(rm(.t.e.m.p., envir = .GlobalEnv))
lapply(quotes, eval, list(x= .t.e.m.p.))
}))
df
#> x c.5..10..15. c.6..11..16. c.7..12..17.
#> 1 5 5 6 7
#> 2 10 10 11 12
#> 3 15 15 16 17
ls(all.names = TRUE)
#> [1] "df" "quotes"
由 reprex package (v0.3.0)
于 2021-05-11 创建
这看起来当然很糟糕,使用 transform
、within
或 tibble
可能是更明智的选择。
如果您不介意在 .GlobalEnv
中创建 x
,并且可能会覆盖它,您可以在 data.frame
.[=34 中使用 <-
=]
quotes<-alist(x, x+1, x+2)
data.frame(x=x <- c(5, 10, 15), lapply(quotes, eval))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
rm(x)
您可以在 local
中调用它,但是 x
不会在 .GlobalEnv
中创建,并且 eval
需要被告知在当前 [=25= 中查找].
local(data.frame(x=x <- c(5, 10, 15), lapply(quotes, eval, environment())))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
也可以将值分配给不同的名称,但此处 eval
需要名称为 x
的 list
。请注意,在这种情况下,TMP 将首先创建或覆盖,如果需要,然后从 .GlobalEnv
.
中使用 rm
删除
data.frame(x=TMP <- c(5, 10, 15), lapply(quotes, eval, list(x=TMP)))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
rm(TMP)
其他(但不是 asked/wanted)的可能性可能正在使用 transform
:
transform(data.frame(x=c(5, 10, 15)), y=lapply(quotes, eval, environment()))
# x y.c.5..10..15. y.c.6..11..16. y.c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
within
:
within(data.frame(x=c(5, 10, 15)), y <- lapply(quotes, eval, environment()))
# x y
#1 5 5, 10, 15
#2 10 6, 11, 16
#3 15 7, 12, 17
或tibble
:
tibble::tibble(x=c(5, 10, 15), y=sapply(quotes, eval, environment()))
## A tibble: 3 x 2
# x y[,1] [,2] [,3]
# <dbl> <dbl> <dbl> <dbl>
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
最后(供参考)问题的预期输出:
x <- c(5, 10, 15)
data.frame(x, lapply(quotes, eval))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
rm(x)
与之前使用 tibble
的答案类似,但为了完整性添加了 data.table
解决方案:
data.table(x=c(5, 10, 15))[, lapply(quotes, eval, envir=environment())]
# V1 V2 V3
# 1: 5 6 7
# 2: 10 11 12
# 3: 15 16 17
正如其他人所提到的,我认为最好的解决方案是使用 tibble()
而不是 data.frame()
。但是,如果你想避免 tibble
依赖,我认为最好的解决方案是创建一个自定义函数 my_frame()
来实现你需要的功能。如果您只在第一列中设置 'defining' 值,这可能相当简单:
my_frame <- function(x, quotes) {
data.frame(x, lapply(quotes, eval, environment()))
}
my_frame(c(5, 10, 15), quotes)
#> x c.5..10..15. c.6..11..16. c.7..12..17.
#> 1 5 5 6 7
#> 2 10 10 11 12
#> 3 15 15 16 17
考虑:
quotes<-alist(x, x+1, x+2)
data.frame(x=c(5, 10, 15), lapply(quotes, eval))
这不起作用,因为 eval
找不到 x
。有没有办法让 eval
识别数据框中定义的变量?我知道我可以将数据框分配给一些变量,然后使用 transform
等函数构建它,但我希望在调用 data.frame
.[=17= 时完成所有这些操作]
对于预期输出的可能版本,我们可以使用:
quotes<-alist(x, x+1, x+2)
x=c(5, 10, 15)
data.frame(x, lapply(quotes, eval))
调试 data.frame(x=c(5, 10, 15), lapply(quotes, eval))
导致:
x <- list(...)
#Error in FUN(X[[i]], ...) : object 'x' not found
这是由于对第二个参数的评估:
lapply(quotes, eval)
#Error in FUN(X[[i]], ...) : object 'x' not found
如果不事先在 environment
.
x
,这里似乎很难找到解决方法
tibble
允许在定义更多变量时使用之前的变量,因为它依赖于使用 quos(...)
而不是 list(...)
的非标准评估来处理参数:
function (..., .rows = NULL, .name_repair = c("check_unique",
"unique", "universal", "minimal"))
{
xs <- quos(...)
is.null <- map_lgl(xs, quo_is_null)
tibble_quos(xs[!is.null], .rows, .name_repair)
}
与tibble
:
tibble::tibble(x=c(1,2,3), result= sapply(quotes,function(quo) eval(quo)))
# A tibble: 3 x 2
x result[,1] [,2] [,3]
<dbl> <dbl> <dbl> <dbl>
1 1 1 2 3
2 2 2 3 4
3 3 3 4 5
然而,这还不是预期的结果,因为 quotes
需要使用 x
按行处理,例如 mapply
:
tibble::tibble(x=c(1,2,3), result = mapply(function(quo,x) eval(quo),quotes,x))
# A tibble: 3 x 2
x result
<dbl> <dbl>
1 1 1
2 2 3
3 3 5
您是否注意到更简单的调用 data.frame(x, y = x)
也不起作用?
data.frame()
使用标准评估,因此在您的情况下,它们将在全球环境中进行评估。
不过,如果您为引号元素命名,您将能够做到 tibble(x, !!!quotes)
,因为 tibble 的工作方式不同。
从技术上讲,您可能可以接受以下内容,我们通过在全局环境中创建一个临时值来作弊,然后在退出时将其删除。
(我用evalq
只是为了能用on.exit
)
quotes<-alist(x, x+1, x+2)
df <- data.frame(
x = c(5, 10, 15) ->> .t.e.m.p.,
evalq({
on.exit(rm(.t.e.m.p., envir = .GlobalEnv))
lapply(quotes, eval, list(x= .t.e.m.p.))
}))
df
#> x c.5..10..15. c.6..11..16. c.7..12..17.
#> 1 5 5 6 7
#> 2 10 10 11 12
#> 3 15 15 16 17
ls(all.names = TRUE)
#> [1] "df" "quotes"
由 reprex package (v0.3.0)
于 2021-05-11 创建这看起来当然很糟糕,使用 transform
、within
或 tibble
可能是更明智的选择。
如果您不介意在 .GlobalEnv
中创建 x
,并且可能会覆盖它,您可以在 data.frame
.[=34 中使用 <-
=]
quotes<-alist(x, x+1, x+2)
data.frame(x=x <- c(5, 10, 15), lapply(quotes, eval))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
rm(x)
您可以在 local
中调用它,但是 x
不会在 .GlobalEnv
中创建,并且 eval
需要被告知在当前 [=25= 中查找].
local(data.frame(x=x <- c(5, 10, 15), lapply(quotes, eval, environment())))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
也可以将值分配给不同的名称,但此处 eval
需要名称为 x
的 list
。请注意,在这种情况下,TMP 将首先创建或覆盖,如果需要,然后从 .GlobalEnv
.
rm
删除
data.frame(x=TMP <- c(5, 10, 15), lapply(quotes, eval, list(x=TMP)))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
rm(TMP)
其他(但不是 asked/wanted)的可能性可能正在使用 transform
:
transform(data.frame(x=c(5, 10, 15)), y=lapply(quotes, eval, environment()))
# x y.c.5..10..15. y.c.6..11..16. y.c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
within
:
within(data.frame(x=c(5, 10, 15)), y <- lapply(quotes, eval, environment()))
# x y
#1 5 5, 10, 15
#2 10 6, 11, 16
#3 15 7, 12, 17
或tibble
:
tibble::tibble(x=c(5, 10, 15), y=sapply(quotes, eval, environment()))
## A tibble: 3 x 2
# x y[,1] [,2] [,3]
# <dbl> <dbl> <dbl> <dbl>
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
最后(供参考)问题的预期输出:
x <- c(5, 10, 15)
data.frame(x, lapply(quotes, eval))
# x c.5..10..15. c.6..11..16. c.7..12..17.
#1 5 5 6 7
#2 10 10 11 12
#3 15 15 16 17
rm(x)
与之前使用 tibble
的答案类似,但为了完整性添加了 data.table
解决方案:
data.table(x=c(5, 10, 15))[, lapply(quotes, eval, envir=environment())]
# V1 V2 V3
# 1: 5 6 7
# 2: 10 11 12
# 3: 15 16 17
正如其他人所提到的,我认为最好的解决方案是使用 tibble()
而不是 data.frame()
。但是,如果你想避免 tibble
依赖,我认为最好的解决方案是创建一个自定义函数 my_frame()
来实现你需要的功能。如果您只在第一列中设置 'defining' 值,这可能相当简单:
my_frame <- function(x, quotes) {
data.frame(x, lapply(quotes, eval, environment()))
}
my_frame(c(5, 10, 15), quotes)
#> x c.5..10..15. c.6..11..16. c.7..12..17.
#> 1 5 5 6 7
#> 2 10 10 11 12
#> 3 15 15 16 17