【问题标题】:In r, use string just as if I had typed it in在 r 中,使用字符串,就像我输入它一样
【发布时间】:2021-12-03 19:17:47
【问题描述】:

我正在处理 r 中真正让我感到困惑的一个方面。我构建的是一行代码调用 str_remove 保存为字符串。如果我将该字符串复制粘贴到我想使用这行代码的位置,它会按预期完美运行。 但是我无法让 r 正确解释此代码。我试过使用例如解析,但用于 str_remove 正则表达式的转义字符会引发错误。

难道没有一种简单的方法可以将字符串视为一行输入的代码吗?

这是我的可重现示例:

制作玩具数据:

maf_list_context <- list(as.data.frame(cbind(c("ATTATCGAATT", "ATTATTTTAAA"), c("this one", "not that one"))),
                     as.data.frame(cbind(c("ATTACGTAATT", "ATTATTTTAAA"), c("this one too", "not that one either")))   )

maf_list_context <- lapply(maf_list_context, function(x)
{colnames(x) <- c("CONTEXT", "want_it")
return(x)
})

这个想法是上下文将是一个函数的参数并且它可以是灵活的,因此用户可以提供任意数量的以逗号分隔的感兴趣的上下文。这些将是 stringr 正则表达式,旨在在一串 11 个碱基中查找 DNA 中的特定上下文。例如,在这里我们可以使用两个感兴趣的上下文。下面的代码将这些组合起来,形成一个表达式,供以后从列表中的数据框中选择适当的行。

context <- "\\w{5}CG\\w{4}, \\w{4}CG\\w{5}"

contextvec <- unlist(str_split(context, pattern = ", "))

contextexpression <- c()

for(i in 1:length(contextvec)){
  
  contextexpression <- paste0(contextexpression, "str_detect(x$CONTEXT, pattern = '", contextvec[i], "') |")
  
}

contextexpression <- str_remove(contextexpression, pattern = " \\|$")

'contextexpression' 现在是:

[1] "str_detect(x$CONTEXT, pattern = '\\w{5}CG\\w{4}') |str_detect(x$CONTEXT, pattern = '\\w{4}CG\\w{5}')"

如果我将此表达式直接粘贴到 apply 中,它会完全按照我的意愿工作。

 > lapply(maf_list_context, function(x){
+   
+   x[str_detect(x$CONTEXT, pattern = '\\w{5}CG\\w{4}') |str_detect(x$CONTEXT, pattern = '\\w{4}CG\\w{5}'), ]
+   
+ })

[[1]]
      CONTEXT  want_it
1 ATTATCGAATT this one

[[2]]
      CONTEXT      want_it
1 ATTACGTAATT this one too

当然,如果我在那里使用字符串,它不会。

> lapply(maf_list_context, function(x){
+   
+   x[contextexpression, ]
+   
+ })

[[1]]
   CONTEXT want_it
NA    <NA>    <NA>

[[2]]
   CONTEXT want_it
NA    <NA>    <NA>

我尝试了许多不同的功能,但没有一个可以使这项工作。有没有办法让 r 像我直接输入一样解释这个字符串?

整个reprex:

if (!require("stringr") {
  install.packages("stringr", dependencies = TRUE)
  library("stringr")

maf_list_context <- list(as.data.frame(cbind(c("ATTATCGAATT", "ATTATTTTAAA"), c("this one", "not that one"))),
                         as.data.frame(cbind(c("ATTACGTAATT", "ATTATTTTAAA"), c("this one too", "not that one either")))   )

maf_list_context <- lapply(maf_list_context, function(x){
  colnames(x) <- c("CONTEXT", "want_it")
  return(x)
})

context <- "\\w{5}CG\\w{4}, \\w{4}CG\\w{5}"

contextvec <- unlist(str_split(context, pattern = ", "))

contextexpression <- c()

for(i in 1:length(contextvec)){
  
  contextexpression <- paste0(contextexpression, "str_detect(x$CONTEXT, pattern = '", contextvec[i], "') |")
  
}

contextexpression <- str_remove(contextexpression, pattern = " \\|$")

maf_list_select <- lapply(maf_list_context, function(x){
  
  x[contextexpression, ]
  
})

【问题讨论】:

  • 你所追求的是eval(parse(text=*))。但是 1) 如果答案是 eval+parse,那么您可能问错了问题; 2)我认为你可能对 R 有点缺乏经验来考虑这样的事情。寻找更简单的方法来做你正在做的事情
  • 嗨,洪,我已经尝试过 eval(parse(text = *))。但是,正如我在帖子中提到的,由于正则表达式,它会引发错误。 h(simpleError(msg, call)) 中的错误:在为函数 'eval' 选择方法时评估参数 'expr' 时出错:'\w' 是开始于 "'\w" 的字符串中无法识别的转义做我正在做的事情,我会欢迎建议!

标签: r string types stringr


【解决方案1】:

我不确定我是否完全遵循您希望输入的内容以及如何应用它,但您的问题似乎与您传递给子集运算符的内容有关,即x[&lt;codehere&gt;]

子集运算符需要一个逻辑向量。当你“粘贴表达式”时,你实际上是在粘贴一个被评估为逻辑向量的表达式,因此它是正确的子集。当您传递变量contextexpression 时,实际上是在传递一个字符串。正如 R 所见:

x[ "str_detect(x$CONTEXT, pattern = '\\w{5}CG\\w{4}') |str_detect(x$CONTEXT, pattern = '\\w{4}CG\\w{5}')", ]

而不是(注意语法高亮的区别):

x[ str_detect(x$CONTEXT, pattern = '\\w{5}CG\\w{4}') |str_detect(x$CONTEXT, pattern = '\\w{4}CG\\w{5}'), ]

您希望将每个上下文应用于列表的每个成员以获取逻辑向量,然后获取子集。

purrr::map2(maf_list_context, contextvec, ~.x[str_detect(.x$CONTEXT, .y), ])

如果您想将contextvec 中的每个项目与maf_list_context 中的每个项目进行比较,那么它有点复杂但可行。

purrr::map2(
  maf_list_context, 
  purrr::map(
    maf_list_context, 
    function(data){
      purrr::reduce(contextvec, 
                    function(prev, cond) str_detect(data$CONTEXT, cond) | prev, 
                    .init = logical(length(contextvec))
      )
    } 
  ),
  ~.x[.y]
)

可能有一种更有效的方法可以将匹配项与maf_list_context 中的项目短路,但一般方法适用。 str_detect 处理单个条件与单个 maf_list 项的比较。 reduce 调用将contextvec 与maf_list_context 中的单个项目的所有比较结果组合为单个布尔值。内部map 遍历maf_list_context。外部map2 遍历由内部map 和maf_list_context 创建的布尔值列表以匹配子集。

如果maf_list_context 有n 个项目,contextvec 有m 个项目:

  • reduce 进行 m 次比较,得到 1 个值
  • map 对 reduce 进行 n 次调用会产生 n 个值
  • map2 对子集 maf_list_context 进行 n 次迭代

【讨论】:

  • 嗨,马库斯,非常感谢您的回答。这似乎在 reprex 上完美运行,但并不是我所追求的。我想要做的是在maf_list_context 中的每个元素中搜索contextvec 中的任何上下文。这里似乎 map2() 将 .x 中的第一个元素应用于 .y 中的第一个元素,将 .x 中的第二个元素应用于 .y 中的第二个元素,依此类推。所以在这里,如果我们从玩具数据中的列表中切换上下文,或者在“上下文”中提供的上下文的顺序,现在 map2 返回一个空列表。
  • 检查我的理解 - 如果您在 maf_list_context 中有 n 个项目,在 contextvec 中有 m 个项目,您最终希望进行 n*m 比较。我将编辑我的答案以扩展此案例的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 2023-01-25
  • 2011-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多