【问题标题】:detect pattern in a data.frame column with string_detect too slow in R在 R 中使用 string_detect 检测到 data.frame 列中的模式太慢
【发布时间】:2021-02-05 07:07:13
【问题描述】:

我有一个包含 50,000 行和 194 列的 data.frame。在名为 "Gene" 的列之一中,有一个或多个条目,始终遵循相同的模式,例如“基因1”或“基因1;基因2”或“基因1:基因2:基因3”。然后我有一个字符向量,其正则表达式模式很长,例如 "\bgene1$|\bgene2$|\bgene3$|\bgene4$..." 总共有 4,000 个模式,即, 4,000 \bgene$

我想在我的 data.frame 的 Gene 列中找到该模式的匹配项

这是我目前使用的代码示例

我无法输出整个 data.frame,因为它太长了

genes <- c("AARS", "AARS1", "SAMD11", "MUTYH", "PEGX", "BRCA1", "APC") # my real number of genes is 3,000

# then I converted the genes' vector to a regexp
genes2 <- paste0("\\b", genes, "\\b")

# then I try the matching
matches <- unique(grep(paste(genes2, collapse = "|"), # tib is my data.frame and Gene the column with the values I want to match
             tib$Gene, value = TRUE, perl = FALSE)) 

# And finally filtering the data.frame
tib2 <- tib %>% dplyr::filter(Gene %in% matches)

但是,当我使用我的真实数据时,grep 出现内存不足错误(设置perl=FALSE),所以我尝试了stringr 库,但完成搜索太慢了:

test <- str_extract_all(tib$Gene.refGene, paste(genes2,collapse="|"))
test2 <- str_detect((tib$Gene.refGene, paste(genes2,collapse="|"))

testtest2 都太慢了

关于如何更新的任何提示

行数较少的示例如下,由@jay.sf 提供

d <- structure(list(gene = c("XY42", "SAMD11:XY20:XY29:XY34:XY82:XY88:XY94", 
"XY17:XY23:XY35:XY36:XY8", "MUTYH:XY43:XY62:XY85:XY91:XY92", 
"AARS1:SAMD11:XY100:XY14:XY3:XY51:XY95", "XY2:XY22:XY28:XY69:XY77", 
"AARS1:XY11:XY17:XY62:XY75", "XY25:PEGX:XY47:XY6:XY76:XY84", 
"APC:XY31:XY36:XY48:XY51:XY65", "BRCA1"), x = c(-1.04042150945666, 
-0.4563032693248, -0.267762662765083, 0.758168827559491, -1.89440229591065, 
0.468157951289336, 0.126909754004865, -0.852405668800981, -0.917059466430073, 
-0.475954635098868)), class = "data.frame", row.names = c(NA, 
-10L))

而且基因列表是固定的genes &lt;- c("AARS", "AARS1", "SAMD11", "MUTYH", "PEGX", "BRCA1", "APC"。我想在Gene列中找到基因列表成员和基因之间的完全匹配,即BRCA1(在基因列表中)应该只匹配data.frame中Gene列中的BRCA1而不是BRCA11。

但请记住,我的真实基因列表有 4,000 个基因,而我的 data.frame 由 50,000 行组成

【问题讨论】:

  • 提示:您可以检查stringr::str_detect 是否适合您。在类似的问题中提出了建议。不确定您是否真的需要一个正则表达式。如果你真的需要单词边界,你将不得不根据你的基因构建一个正则表达式树。
  • @WiktorStribiżew,谢谢,我也试过str_detect,但它也太慢了,我会更新我的帖子
  • 您能否提供一个可复制的小型数据框示例。不清楚确切您在做什么(即,您是否希望匹配与gene 列位于同一行)?一个带有预期输出的小例子会很有帮助。
  • @Andrew,谢谢,是的,我将发布 jay.sf 的示例,因为他概括了我的想法
  • @jay.sf,抱歉直到我刷新浏览器才显示。我现在就试试!!

标签: r stringr


【解决方案1】:

我不确定您的输入和输出。但是假设这样的数据,

d
#                                     gene          x
# 1                                   XY42 -1.0404215
# 2   SAMD11:XY20:XY29:XY34:XY82:XY88:XY94 -0.4563033
# 3                XY17:XY23:XY35:XY36:XY8 -0.2677627
# 4         MUTYH:XY43:XY62:XY85:XY91:XY92  0.7581688
# 5  AARS1:SAMD11:XY100:XY14:XY3:XY51:XY95 -1.8944023
# 6                XY2:XY22:XY28:XY69:XY77  0.4681580
# 7              AARS1:XY11:XY17:XY62:XY75  0.1269098
# 8           XY25:XY46:XY47:XY6:XY76:XY84 -0.8524057
# 9          XY22:XY31:XY36:XY48:XY51:XY65 -0.9170595
# 10                                  XY36 -0.4759546

您可以使用strsplit 拆分: 处的基因,首先,将match 与您的genes 向量一起拆分。

## all genes from d
d.genes.0 <- sort(unique(unlist(strsplit(d$gene, "\\:"))))
## genes from d existing in `genes` vector `as.numeric`.
d.genes.1 <- as.numeric(na.omit(match(genes, d.genes.0)))

然后,我们将分裂的基因(如上)转换为factors,并使用d.genes.0作为因子水平;利用factors 的数字转换,我们最终匹配数字而不是字符串。

rw <- sapply(strsplit(d$gene, "\\:"), function(x) 
  any(d.genes.1 %in% as.numeric(factor(x, levels=d.genes.0))))
d[rw, ]
#                                    gene          x
# 2  SAMD11:XY20:XY29:XY34:XY82:XY88:XY94 -0.4563033
# 4        MUTYH:XY43:XY62:XY85:XY91:XY92  0.7581688
# 5 AARS1:SAMD11:XY100:XY14:XY3:XY51:XY95 -1.8944023
# 7             AARS1:XY11:XY17:XY62:XY75  0.1269098

用 > 4k 基因和 50k 行测试,应该可以工作。


数据:

d <- structure(list(gene = c("XY42", "SAMD11:XY20:XY29:XY34:XY82:XY88:XY94", 
"XY17:XY23:XY35:XY36:XY8", "MUTYH:XY43:XY62:XY85:XY91:XY92", 
"AARS1:SAMD11:XY100:XY14:XY3:XY51:XY95", "XY2:XY22:XY28:XY69:XY77", 
"AARS1:XY11:XY17:XY62:XY75", "XY25:XY46:XY47:XY6:XY76:XY84", 
"XY22:XY31:XY36:XY48:XY51:XY65", "XY36"), x = c(-1.04042150945666, 
-0.4563032693248, -0.267762662765083, 0.758168827559491, -1.89440229591065, 
0.468157951289336, 0.126909754004865, -0.852405668800981, -0.917059466430073, 
-0.475954635098868)), class = "data.frame", row.names = c(NA, 
-10L))

【讨论】:

  • 谢谢@jay.sf,但问题是我的基因是 4,000,当我使用 grep 时,如果 perl=T,它会抱怨“模式变长”,或者如果 perl=F,则会出现内存不足
  • @user2380782 我明白了。基因序列是有序的还是无序的?例如。是4, 2, 3, 5, 1 可能还是只是1, 2, 3, 4, 5
  • 成功了,一个简单的问题,匹配只是完全正确的吗?例如,如果基因列表中的一个基因被命名为AAS,而在基因列中是AAS1,它就不会匹配,不是吗?
  • @user2380782 数据框中的基因和向量中的基因都被拆分为唯一值并进行匹配。所以它实际上是因子级别的匹配,而不是超出内存限制的字符串匹配。因此只匹配唯一值。
  • 优秀。这仍然需要时间,但这是我需要忍受的。谢谢!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多