微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在嵌套对象的函数环境中找不到对象

如何解决在嵌套对象的函数环境中找不到对象

我有一个代码片段,我试图将其转换为函数。此函数应该在手动输入字段中查找潜在的拼写错误。该代码段有效,您可以像这样使用 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,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)

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

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

这让我遇到了相同的“一元运算符”错误。我不确定接下来要尝试什么。我好像在绕圈子。对导致此问题的原因以及如何解决此问题的任何见解将不胜感激。

解决方法

我认为您指向的帖子与此处无关。我认为您的问题与执行环境无关。问题实际上是您如何处理将变量传递给您的函数。当您创建 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,...){
  col <- rlang::ensym(.string_col)
  .df <- .df %>%
    add_count(!!col,name = "Freq_name") %>%
    distinct(!!col,.key = ".Nest") %>%
    mutate(Mapped_n = list(imap_dfr(.x = .Nest %>% pull(!!col),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)
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。