【问题标题】:Only strings can be converted to symbols within a function in R只有字符串可以在 R 中的函数内转换为符号
【发布时间】:2020-12-02 10:27:00
【问题描述】:

我有一个函数,旨在对从具有许多手动输入字段的各种来源获得的数据进行操作。由于我不知道这些文件中使用的布局或命名约定会发生什么,我希望它“扫描”数据框以查找具有字符串“fix”、“name”或“agent”的列,并且将该列更改为名为“Firm”的新列,然后继续对该列的条目进行字符串清理,最后删除原始列。我已经让它与我已经拥有的一些 CSV 一起工作,但现在遇到了这个错误:只有字符串可以转换为符号。我已经检查了这个线程ERROR: Only strings can be converted to symbols,但无济于事。

这是目前的功能:

clean_firm_names2 <- function(df){
  df <- df %>%
    mutate(Firm := !!rlang::sym(grep(pattern = '(AGENT)|(NAME)|(FIX)',x = colnames(.), ignore.case = T, value = T)) %>% 
             str_replace_all(pattern = "(\\W)+"," ") %>% 
             ...str manipulations...
             str_squish()) %>%
    dplyr::select(-(!!rlang::sym(grep(pattern = '(AGENT)|(NAME)|(FIX)',x = colnames(.), ignore.case = T, value = T))))
  return(df)
}

我尝试在 grep() 函数周围使用 as.character() ,但这并没有解决问题。我查看了该函数要对其进行操作的 CSV,并且所有列名都是字符串。我使用 vroom() 在 CSV 中读取,与我的其他 CSV 一样,效果很好,所有列名都出现了。我可以在 df 上执行其他 dplyr 功能,这表明 df 在其他方面表现正常。关于为什么该功能仅在我的一些 CSV 上阻塞但在其他 CSV 上按预期工作,我已经没有想法了。有没有人遇到过类似的问题或对可能导致此错误的原因有任何线索?这是我第一次使用 SO——如果这个问题不是很清楚,我很抱歉。我会根据需要尝试和编辑。

谢谢!

【问题讨论】:

  • 为可能面临此问题的其他人重申:正如@Artem Sokolov 在下面建议的那样,此代码在返回字符串向量而不是单个字符串的情况下失败(结果,在这种情况下, 灵活的正则表达式)。

标签: r symbols quoting rlang quasiquotes


【解决方案1】:

请注意,grep() 返回匹配项的索引(整数),而不是匹配项本身(字符串)。整数索引可以直接传递给dplyr::rename,所以也许以下可能会更好?

i <- grep(pattern = '(AGENT)|(NAME)|(FIX)', x = colnames(df), ignore.case = T, value = T)
df <- df %>%
  rename(Firm = i) %>%
  mutate(Firm = ...str manipulations... )

(这里有一个隐含的假设,即您的 grep() 返回一个 single 索引。处理多个匹配项可能需要额外的代码。)

【讨论】:

  • 感谢您对原因的解释——我尝试了这个,也尝试将 grep 命令直接输入到rename(Firm = grep(...)) 以进行简洁,但都无法正常工作。在这两种情况下,我都会收到以下错误:Problem with 'mutate()'; input 'Firm'. object 'Firm' not found; Input is ''%&gt;%'(...)'. 此外,由于某种原因,如果我只选择一个可能的匹配词,例如“(NAME)”或“(FIX)”,前面的代码将起作用,但该选项失败使用 ` | `。 grep() 会不会因为这个正则表达式而窒息?
  • @SGE 两个问题:1)当您将grep() 的输出提供给rename() 时,它是否返回单个索引? 2) rename 是否正确输出了一个数据框,其中您的 agent/name/fix 列被重命名为 Firm?
  • 天啊。你是对的——仔细检查 Q1,我发现它与目标列之外的另一列(preFIX)匹配,这导致了错误。当我解决 1 中的双重匹配时,2 成功执行。我现在很好奇如何使它作用于每个匹配的索引。无论如何,这里的协议是什么?如果您对此有任何建议,我当然会感谢您的意见!尽管我认为这完全是一个不同的问题。再次感谢。
  • @SGE 如果要避免前缀匹配,可以考虑使用^ to designate the beginning of the string