【问题标题】:What is causing 'object not found' error in filter() with the across() function?是什么导致使用 cross() 函数在 filter() 中出现“找不到对象”错误?
【发布时间】:2021-07-22 18:27:21
【问题描述】:

此函数从我的数据集中过滤/选择一个或多个变量并将其写入新的 CSV 文件。调用该函数时出现“找不到对象”错误。这是函数:

    extract_ids <-  function(filename, opp, ...) {
  
  #Read in data
  df <- read_csv(filename)
  
  #Remove rows 2,3
  df <- df[-c(1,2),]
    
    #Filter and select
    df_id <- filter(df, across(..., ~ !is.na(.x)) & gc == 1) %>%
      select(...) #not sure if my use of ... here is correct
    
    #String together variables for export file path
    path <- c("/Users/stephenpoole/Downloads/",opp,"_",...,".csv") #not sure if ... here is correct
    
    #Export the file
    write_csv(df_id, paste(path,collapse=''))
    
  
}

这里是函数调用。我试图让列“摆脱”和“cintid”。

extract_ids(filename = "farmers.csv",
            opp = "farmers",
            rid, cintid)

当我运行它时,我收到以下错误:

 Error: Problem with `filter()` input `..1`.
ℹ Input `..1` is `across(..., ~!is.na(.x)) & gc == 1`.
x object 'cintid' not found

cintid 列正确并出现在数据中。我也试过只用一列运行它,去掉,得到同样的“找不到对象”错误。

【问题讨论】:

  • 如果你要传递多个值,它应该像filter(df, across(c(...), ~ !is.na(.x)) 这样这些列都在第一个参数中。如果您包含一个简单的reproducible example 以及可用于测试和验证可能解决方案的示例输入,则更容易为您提供帮助。
  • @StephenPoole 我刚刚更新了我的答案,解决了您关于文件路径中的变量名称的问题。

标签: r dplyr tidyverse


【解决方案1】:

如果给across()传递多个值,需要在第一个参数中收集,否则会扩散到across()的其他参数中。试试

filter(df, across(c(...), ~ !is.na(.x)) 

否则,除第一个值之外的每个值都将作为参数传递给您在 across() 中指定的函数

【讨论】:

    【解决方案2】:

    很抱歉在我的previous suggestion 中省略了这一点。不幸的是,your original question 在我将其发布为答案之前已关闭:

    如果您希望您的函数类似于 dplyr,这里有一些 您可以进行的修改。将您的函数头写为 function(filename, opp, ...) 逐字逐句。然后,替换!is.na(ID) across(..., ~ !is.na(.x)) 逐字逐句。现在,您可以致电 extract_ids() 并且,就像使用任何 dplyr 动词一样,您可以 指定要过滤掉NAs 的任何列选择: extract_ids(filename = "farmers.csv", opp = "farmers", rid, another_column_you_want_without_NAs).

    找不到对象

    正如MrFlicktheir comment 中正确建议的那样,您应该用c() 包裹...,因此您传入... 的所有内容都被解释为across() 的第一个参数:单个tidy-selection来自df 的列数:

    extract_ids <-  function(filename, opp, ...) {
      # ...
    
      # Filter and select
      df_id <- df %>%
        # This format is preferred for dplyr workflows with pipes (%>%).
        filter(across(c(...), ~ !is.na(.x)) & gc == 1) %>%
        select(...)
    
      # ...
    }
    

    如果没有这种预防措施,R 会将ridcintid 解释为across() 的多个参数,而不是简单地由第一个参数命名的列(tidy-selection)。

    文件路径中的变量名

    要在文件路径中获取这些变量名称,请使用

    extract_ids <-  function(filename, opp, ...) {
      # ...
      
      # Expand the '...' into a list of given variable names, which will get pasted.
      path <- c("/Users/stephenpoole/Downloads/", opp, "_", match.call(expand.dots = FALSE)$`...`, ".csv")
    
      # ...
    }
    

    尽管您可能需要考虑替换 match.call(expand.dots = FALSE)$`...`,它目前将变量名混合在一起:

    "/Users/stephenpoole/Downloads/farmers_ridcintid.csv"
    

    在完全相同的地方,您可以使用表达式paste(match.call(expand.dots = FALSE)$`...`, collapse = "-"),它将使用- 分隔这些变量名

    "/Users/stephenpoole/Downloads/farmers_rid-cintid.csv"
    

    或您选择的任何其他提供有效文件名的分隔符。

    【讨论】:

    • 这很好,谢谢。如果我想为参数中指定的每一列(即,rid、cintid)编写两个单独的 CSV,你能告诉我如何更改代码吗?这是我最初的目标,但我知道我没有在问题中具体说明。
    • @StephenPoole 这取决于您是否希望每个 CSV 过滤掉一行,其中 *ids 中的 any 为空白。也就是说,您是否真的希望 farmers_rid.csv 忽略 cintid 为空白的行,即使 rid 本身存在?或者您是否希望它仅省略 rid 本身为空白的那些行?
    • @StephenPoole 嗯...在这种情况下,您需要在执行dplyr 操作之前... 分解为变量名:@987654358 @。然后将所有内容(dplyr 工作流程和pathwrite_csv())替换为:sapply(X = all_vars, FUN = function(var){df_id &lt;- df %&gt;% filter(!is.na(.data[[var]]) &amp; gc == 1) %&gt;% select(var); path &lt;- c("/Users/stephenpoole/Downloads/", opp, "_", var, ".csv"); write_csv(df_id, paste(path,collapse=''))})。我认为可以,但我还没有测试过。
    • @StephenPoole 这个想法是match.call(expand.dots = FALSE)$`...` 捕获(作为symbols)您传递给extract_ids () 的所有列名,as.character() 将这些名称转换为character 字符串,存储在all_vars。例如:调用extract_ids(filename = "farmers.csv", opp = "farmers", rid, cintid) 给我们一个all_varsc("rid", "cintid")。然后,在sapply() 调用中,将每个名称按var 顺序输入FUN。对于每个名称("rid""cintid"),FUN 执行 dplyr 工作流并为该列名称编写 .csv
    • @StephenPoole 换句话说,你是对的当你说 "all_vars...成为..."。致电extract_ids(filename = "farmers.csv", opp = "farmers", rid, cintid)` 将为您提供all_varsc("rid", "cintid")。调用sapply(X = all_vars, FUN = function(var){...})迭代地all_vars 的每个元素传递给FUN。即,为var = "rid"var = "cintid" 中的每一个执行FUN = function(var){...}。这就是sapply() 背后的想法:它将对X = all_vars 的每个元素执行FUN,将元素作为arg。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    相关资源
    最近更新 更多