【问题标题】:Object not found in function environment for nested objects在嵌套对象的函数环境中找不到对象
【发布时间】:2021-01-05 18:26:15
【问题描述】:

我有一个代码 sn-p,我正在尝试将其转换为函数。此功能应该在手动输入字段中查找潜在的拼写错误。 sn-p 可以工作,您可以使用 tidyverse 包中的 starwars 数据进行尝试:

require(tidyverse)
require(rlang)            # loaded for {{ to force function arguments as well as the with_env() function
require(RecordLinkage)    # loaded for the jarowinkler() function

starwars_cleaning <- starwars %>%
  add_count(name, name = "Freq_name") %>%   # this keeps track of which spelling is more frequent
  distinct(name, .keep_all = T) %>%         # this prevents duplicated comparisons and self-comparisons
  nest_by(homeworld, .key = ".Nest") %>%
  mutate(Mapped = list(imap_dfr(.x = .Nest$name,
                                .f = ~jarowinkler(str1 = .x,
                                                  str2 = .Nest$name[-.y]) %>% 
                                  list() %>% 
                                  tibble(Score_n = ., Match_n = list(.Nest$name[-.y]),
                                         Freq_n = list(.Nest$Freq_name[-.y]))
                                
  )))

该函数应接受要嵌套的变量(省略号)和要在其中查找潜在拼写错误匹配项的变量作为参数。现在,它看起来像这样:

string_matching <- function(.df, .string_col, ...){
  .df$.tmp_string <- .df %>% select({{.string_col}})
  .df <- .df %>%
    add_count(.tmp_string, name = "Freq_name") %>%
    distinct(.tmp_string, .keep_all = T) %>% 
    nest_by(..., .key = ".Nest") %>%
    mutate(Mapped_n = list(with_env(env = current_env(),  # same error with or without specifying the execution environment for imap
                                    expr = imap_dfr(.x = .Nest$.tmp_string,
                                                    .f = ~jarowinkler(str1 = .x,
                                                                      str2 = .Nest$.tmp_string[-.y]) %>% 
                                                      list() %>% 
                                                      tibble(Score_n = ., Match_n = list(.Nest$.tmp_string[-.y]),
                                                             Freq_n = list(.Nest$Freq_name[-.y]))
                                                    )
                                    ))
           )
  return(.df)
}
starwars %>% 
  string_matching(name, homeworld)

显然,在星球大战的数据上,它不是很有用。我削减了这段代码的一些功能以获得 MWE——但这就是我的想法。当我像这样将代码包装在一个函数中时,它返回invalid argument to unary operator(显然是由[-.y]引起的)。我在阅读this post 后尝试了force() 命令,因为这个问题显然出现了很多。由于当前的错误和那篇文章,我认为问题可能与导致imap_dfr() 以某种方式丢失数据的函数环境有关。我试图在with_env() 中包装对map 的调用,并指示它使用函数环境而不是它自己的环境。我还尝试通过将中间对象分配给全局环境来分解函数,以便可以在函数的映射步骤中找到它:

assign(x = "TEMP", value = .df$.Nest, envir = global_env())

这让我遇到了同样的“一元运算符”错误。我不确定下一步该尝试什么。我似乎在绕圈子。任何有关导致此问题的原因以及如何解决此问题的见解将不胜感激。

【问题讨论】:

    标签: r function purrr nested-function


    【解决方案1】:

    我认为您所指的帖子与此处无关。我认为您的问题与执行环境无关。问题实际上是您如何处理将变量传递给您的函数。当您创建tmp_string 时,您正在调用select(),它返回的是一个小标题,而不是列值的向量。相反,请使用 pull() 提取这些值。

    string_matching <- function(.df, .string_col, ...){
      .df$.tmp_string <- .df %>% pull({{.string_col}})
      .df <- .df %>%
        add_count(.tmp_string, name = "Freq_name") %>%
        distinct(.tmp_string, .keep_all = T) %>% 
        nest_by(..., .key = ".Nest") %>%
        mutate(Mapped_n = list(with_env(env = current_env(),  # same error with or without specifying the execution environment for imap
                                        expr = imap_dfr(.x = .Nest$.tmp_string,
                                                        .f = ~jarowinkler(str1 = .x,
                                                                          str2 = .Nest$.tmp_string[-.y]) %>% 
                                                          list() %>% 
                                                          tibble(Score_n = ., Match_n = list(.Nest$.tmp_string[-.y]),
                                                                 Freq_n = list(.Nest$Freq_name[-.y]))
                                                        )
                                        ))
               )
      return(.df)
    }
    

    或者您可以编写代码来完全避免需要该临时列

    string_matching <- function(.df, .string_col, ...){
      col <- rlang::ensym(.string_col)
      .df <- .df %>%
        add_count(!!col, name = "Freq_name") %>%
        distinct(!!col, .keep_all = T) %>% 
        nest_by(..., .key = ".Nest") %>%
        mutate(Mapped_n = list(imap_dfr(.x = .Nest %>% pull(!!col),
                                                        .f = ~jarowinkler(str1 = .x,
                                                                   str2 = (.Nest %>% pull(col))[-.y]) %>% 
                                                          list() %>% 
                                                          tibble(Score_n = ., Match_n = list((.Nest %>% pull(col))[-.y]),
                                                                 Freq_n = list(.Nest$Freq_name[-.y]))
                                        ))
        )
      return(.df)
    }
    

    【讨论】:

      最近更新 更多