如何使用 purrr::pmap 在 R 中调用用户定义的函数
How to use purrr::pmap to invoke a user-defined function in R
我想使用 purrr
库的 map
或 pmap
调用函数 wrap_vr
。
首先,我不明白为什么我必须使用df$v1
和df$v2
来将变量传递给函数。为什么不只 v1
和 v2
?
其次,当我尝试使用 pmap
时我的错误是什么?
library(tidyverse)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function(df, vr, tit, ylab){
ggplot(data = df, aes(date, all_of(vr))) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ cy)
}
wrap_vr(df, df$v1, "title_1", "ylabel_1")
wrap_vr(df, df$v2, "title_2", "ylabel_2")
list_1 <- list(df, list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
# This gives an error
pmap(list_1, ~wrap_vr(.x))
#> Error: Element 2 of `.l` must have length 1 or 4, not 2
Created on 2021-07-06 by the reprex package (v2.0.0)
更改代码中的一些内容可以解决此问题。首先,您的数据集不应作为列表读取,因此您可以将其从 list_1
.
中取出
list_1 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
从那里,您可以像这样表达您的 pmap 调用以获得您想要的结果:
pmap(list_1, ~wrap_vr(df, ..1, ..2, ..3))
除了列出的两个问题之外,还有一个问题,您将 date 和 cy 列作为常量传递,假设它始终存在。
不过,我的建议是使用这些列作为默认名称。
所以
- 您的第一个问题可以使用
.data[[vars]]
解决
- 你的第二个问题可以通过从列表中删除 df 来解决
- 此外,建议您进一步修改 custom_function,使用两个默认值的参数。
- 还建议在 last 中使用带有默认值的 df 参数
- 因此,在您的函数中,您必须向其传递三个参数,其他参数将使用默认值。
演示
library(tidyverse)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function( vr, tit, ylab, c1 = 'date', c2 = 'cy', df = df){
df %>% ggplot(aes(.data[[c1]], .data[[vr]])) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ .data[[c2]])
}
wrap_vr( 'v1', "title_1", "ylabel_1")
wrap_vr( 'v2', "title_2", "ylabel_2")
list_1 <- list(list('v1', 'v2'), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pmap(list_1, ~wrap_vr(..1, ..2, ..3))
#> [[1]]
#>
#> [[2]]
由 reprex package (v2.0.0)
于 2021-07-06 创建
在这种情况下使用 pmap
将导致在控制台(或降价内)打印空列表。因为 wrap_vr()
是由它的副作用调用的(显示图形)并且没有 return 任何东西,所以最好使用这样的 pwalk()
函数:
关于写 v1
而不是 df$v1
我们需要修改 wrap_vr()
来考虑 v1
需要存储在列表中的事实一个表达式(以避免“找不到对象 v1”错误)。
library(tidyverse)
library(rlang)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function(df, vr, tit, ylab){
print(
ggplot(data = df, aes(date, all_of(vr))) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ cy))
}
list_1 <- list(list(df, df), list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_1, wrap_vr)
选项 2
#to avoid calling df twice inside the list
list_2 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_2, wrap_vr, df = df)
选项 3
#or quoting the column names
#because column names will go inside a list, we'll need a mechanism to avoid evaluation.
wrap_vr_expr <- function(df, vr, tit, ylab){
print(
ggplot(data = df, aes(date, eval_tidy(vr))) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ cy))
}
list_3 <- list(list(df, df), list(expr(v1), expr(v2)), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_3, wrap_vr_expr)
我想使用 purrr
库的 map
或 pmap
调用函数 wrap_vr
。
首先,我不明白为什么我必须使用df$v1
和df$v2
来将变量传递给函数。为什么不只 v1
和 v2
?
其次,当我尝试使用 pmap
时我的错误是什么?
library(tidyverse)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function(df, vr, tit, ylab){
ggplot(data = df, aes(date, all_of(vr))) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ cy)
}
wrap_vr(df, df$v1, "title_1", "ylabel_1")
wrap_vr(df, df$v2, "title_2", "ylabel_2")
list_1 <- list(df, list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
# This gives an error
pmap(list_1, ~wrap_vr(.x))
#> Error: Element 2 of `.l` must have length 1 or 4, not 2
Created on 2021-07-06 by the reprex package (v2.0.0)
更改代码中的一些内容可以解决此问题。首先,您的数据集不应作为列表读取,因此您可以将其从 list_1
.
list_1 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
从那里,您可以像这样表达您的 pmap 调用以获得您想要的结果:
pmap(list_1, ~wrap_vr(df, ..1, ..2, ..3))
除了列出的两个问题之外,还有一个问题,您将 date 和 cy 列作为常量传递,假设它始终存在。
不过,我的建议是使用这些列作为默认名称。
所以
- 您的第一个问题可以使用
.data[[vars]]
解决
- 你的第二个问题可以通过从列表中删除 df 来解决
- 此外,建议您进一步修改 custom_function,使用两个默认值的参数。
- 还建议在 last 中使用带有默认值的 df 参数
- 因此,在您的函数中,您必须向其传递三个参数,其他参数将使用默认值。
演示
library(tidyverse)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function( vr, tit, ylab, c1 = 'date', c2 = 'cy', df = df){
df %>% ggplot(aes(.data[[c1]], .data[[vr]])) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ .data[[c2]])
}
wrap_vr( 'v1', "title_1", "ylabel_1")
wrap_vr( 'v2', "title_2", "ylabel_2")
list_1 <- list(list('v1', 'v2'), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pmap(list_1, ~wrap_vr(..1, ..2, ..3))
#> [[1]]
#>
#> [[2]]
由 reprex package (v2.0.0)
于 2021-07-06 创建在这种情况下使用 pmap
将导致在控制台(或降价内)打印空列表。因为 wrap_vr()
是由它的副作用调用的(显示图形)并且没有 return 任何东西,所以最好使用这样的 pwalk()
函数:
关于写 v1
而不是 df$v1
我们需要修改 wrap_vr()
来考虑 v1
需要存储在列表中的事实一个表达式(以避免“找不到对象 v1”错误)。
library(tidyverse)
library(rlang)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function(df, vr, tit, ylab){
print(
ggplot(data = df, aes(date, all_of(vr))) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ cy))
}
list_1 <- list(list(df, df), list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_1, wrap_vr)
选项 2
#to avoid calling df twice inside the list
list_2 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_2, wrap_vr, df = df)
选项 3
#or quoting the column names
#because column names will go inside a list, we'll need a mechanism to avoid evaluation.
wrap_vr_expr <- function(df, vr, tit, ylab){
print(
ggplot(data = df, aes(date, eval_tidy(vr))) +
geom_line(color = "steelblue", size = 1) +
labs(title = tit,
y = ylab, x = "") +
facet_wrap(~ cy))
}
list_3 <- list(list(df, df), list(expr(v1), expr(v2)), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_3, wrap_vr_expr)