将变量名称作为参数从外部函数传递到 R 中的内部函数时出现问题?

Posted

技术标签:

【中文标题】将变量名称作为参数从外部函数传递到 R 中的内部函数时出现问题?【英文标题】:Issues in passing variable names as arguments from outer function to inner function in R? 【发布时间】:2020-09-27 14:35:37 【问题描述】:

我正在尝试使流程自动化并创建一个外部函数来运行几个较小的内部函数,但 functionvariable names 作为参数会导致错误:

当我单独运行以下函数时,它可以正常工作:

gapminder <- read.csv("https://raw.githubusercontent.com/swcarpentry/r-novice-gapminder/gh-pages/_episodes_rmd/data/gapminder-FiveYearData.csv")

################ fn_benchmark_country ################

fn_benchmark_country  <- function(bench_country = India)
  
  bench_country = enquo(bench_country)

  gapminder_benchmarked_wider <- gapminder %>% 
                                  select(country, year, gdpPercap) %>% 
                                  pivot_wider(names_from = country, values_from = gdpPercap) %>% 
                                  arrange(year) %>% 
                                  
                                  mutate(across(-1, ~ . - !!bench_country))
                                  
  # Reshaping back to Longer
  gapminder_benchmarked_longer <- gapminder_benchmarked_wider %>% 
                                  pivot_longer(cols = !year, names_to = "country", values_to = "benchmarked") 
 
  # Joining tables
  gapminder_joined <- left_join(x = gapminder, y = gapminder_benchmarked_longer, by = c("year","country"))

  # converting to factor
  gapminder_joined$country <- as.factor(gapminder_joined$country)
  
  return(gapminder_joined)  


################ ----------------------------- ################

# Calling function
fn_benchmark_country(Vietnam) 

country     year     pop  continent  lifeExp    gdpPercap   benchmarked

Afghanistan 1952    8425333 Asia    28.80100    779.4453    232.879565
Afghanistan 1957    9240934 Asia    30.33200    820.8530    230.791034

但是当我在外部函数中运行它时,它会给我错误:

fn_run_all <-function(bench_country = India, year_start = 1952, year_end = 2007)
  
  bench_country = bench_country
  year_start = year_start
  year_end = year_end
  
  fn_benchmark_country(bench_country)


fn_run_all()

Error in fn_run_all() : object 'India' not found

如果我将enquo 添加到参数中,我仍然会收到如下所示的错误“

fn_run_all <-function(bench_country = India, year_start = 1952, year_end = 2007)
  
  bench_country = enquo(bench_country)
  year_start = year_start
  year_end = year_end
  
  fn_benchmark_country(bench_country)


fn_run_all()

Error: Problem with `mutate()` input `..1`. x Base operators are not defined for quosures. Do you need to unquote the quosure? # Bad: lhs - myquosure # Good: lhs - !!myquosure i Input `..1` is `across(-1, ~. - bench_country)`.

不知道如何解决这个问题,将不胜感激!

从这里添加新的相关问题

由于最后一次内部函数调用fn_create_plot()而出现错误

由于在情节的creating dynamic subtitle 中使用bench_country 而发生相同类型的问题,但这次我使用了 但仍然遇到问题

fn_run_all <-function(bench_country = India, year_start = 1952, year_end = 2007)
  

  year_start = year_start
  year_end = year_end
  
  fn_benchmark_country(bench_country)
  
  fn_year_filter(gapminder_joined, year_start, year_end) %>% 
  
  fn_create_plot(., year_start, year_end, bench_country)


fn_run_all(Vietnam, 1967, 2002)

Error in sprintf("Benchmarked %i in blue line \nFor Countries with pop > 30000000 \n(Chart created by ViSa)", : object 'Vietnam' not found

功能代码供参考

################ fn_create_plot ################
  
fn_create_plot <- function(df, year_start, year_end, bench_country )

                  
                  
                  # plotting
                      ggplot(df) +
                        
                      geom_vline(xintercept = 0, col = "blue", alpha = 0.5) +
    
                      geom_label( label="India - As Benchamrking line", x=0, y="United States",
                        label.padding = unit(0.55, "lines"), # Rectangle size around label
                        label.size = 0.35, color = "black") +
                      
                      geom_segment(aes(x = benchmarked_start, xend = benchmarked_end,
                                       y = country, yend = country,
                                       col = continent), alpha = 0.5, size = 7) +
                      
                      geom_point(aes(x = benchmarked, y = country, col = continent), size = 9, alpha = .6) +
                      
                      geom_text(aes(x = benchmarked_start + 8, y = country,
                                    label = paste(country, round(benchmarked_start))),
                                col = "grey50", hjust = "right") +
                      
                      geom_text(aes(x = benchmarked_end - 4.0, y = country,
                                    label = round(benchmarked_end)),
                                col = "grey50", hjust = "left") +
                    
                      
                      # scale_x_continuous(limits = c(20,85)) +
                      
                      scale_color_brewer(palette = "Pastel2") +
                      
                      labs(title = sprintf("GdpPerCapita Differenece with India (Starting point at %i and Ending at %i)",year_start, year_end),
                           subtitle = sprintf("Benchmarked %i in blue line \nFor Countries with pop > 30000000 \n(Chart created by ViSa)", bench_country),
                           col = "Continent", x = sprintf("GdpPerCap Difference at %i & %i", year_start, year_end) ) +
                      
                  # background & theme settings
                      theme_classic() +
                      
                      theme(legend.position = "top", 
                            axis.line = element_blank(),
                            axis.ticks = element_blank(),
                            axis.text = element_blank()
                            )


################ ----------------------------- ################

【问题讨论】:

【参考方案1】:

当您使用enquo() 时,您还需要在函数中调用相关变量时使用!!。这有效:

fn_run_all <-function(bench_country = India, year_start = 1952, year_end = 2007)
  
  bench_country = enquo(bench_country)
  year_start = year_start
  year_end = year_end
  
  fn_benchmark_country(!! bench_country)


fn_run_all()

您也可以将enquo()!! 替换为隧道

fn_run_all <-function(bench_country = India, year_start = 1952, year_end = 2007)
  
  year_start = year_start
  year_end = year_end
  
  fn_benchmark_country( bench_country )


fn_run_all()

【讨论】:

感谢 的解决方案和建议。使用enquo!! 总是让我感到困惑。我想 从现在开始对我来说会是一个更好的选择。再次感谢!! 是的,RStudio 实际上鼓励使用 而不是enquo()!!,因为它造成了混乱。 是的,我同意,它非常令人困惑,即使我使用了,这次我又遇到了另一个内部函数的相同问题。从从此处添加新的相关问题更新了此内容 研究使用glue而不是sprintf:glue.tidyverse.org

以上是关于将变量名称作为参数从外部函数传递到 R 中的内部函数时出现问题?的主要内容,如果未能解决你的问题,请参考以下文章

将对象作为参数传递给函数

将作为变量名的函数参数传递到 R 函数中的公式中?

C言语指针变量作为函数参数

将字符串传递给 R 函数参数,但稍后用作另一个函数的参数名称

函数名称空间与作用域

将“继续”从函数内部传递到 Python 中的外部循环