【问题标题】:Efficient way to iterate over two lists (nested loop alternative)迭代两个列表的有效方法(嵌套循环替代方案)
【发布时间】:2017-03-06 12:04:31
【问题描述】:

我有两个数据框,SCR 和SpecificSpecies。 SCR中的项目名称部分包含Specific Species中列出的物种。

SpecificSpecies$Species
S cerevisiae
Daucus carota

SCR$MESH_HEADINGS
tetracycline CMT-3 
zrg17 protein, S cerevisiae
EP4 glycoprotein, Daucus carota

我正在尝试获取仅包含那些没有任何匹配物种的条目的 SCR 子集。在上述情况下,该列表将只是

tetracycline CMT-3.

我学会这样做的方法是使用嵌套循环,将 SCR 中的每个条目与 SpecificSpecies 中的每个条目进行比较。当没有找到匹配项时,将 SCR 的行追加到新表中:

For each row in SCR {
  SpeciesNumber <- 1
  match <-NULL
  while ((is.null(match)) & (SpeciesNumber < length(SpecificSpecies$Species))) {
  if (grepl(SpecificSpecies$Species[SpeciesNumber], SCR[row,]$MESH_HEADING)){
    match <- TRUE}
  SpeciesNumber <- SpeciesNumber + 1}
  if ((is.null(match) & SpeciesNumber == length(SpecificSpecies$Species)) {
    speciesNoMatch = rbind(speciesNoMatch, SCR[row])}
}}

但这非常慢,SCR 中有 65,000 个条目,SpecificSpecies 中有大约 1500 个条目。有没有办法用 lapply 像这样嵌套?或者其他一些我不熟悉的可以在这里有所帮助的功能?

我确信这是一个糟糕的代码。我是一名医学图书馆员,有时必须使用 R 进行数据分析,所以我的编程技能非常有限,但通常只要它们最终有效,我的解决方案是否丑陋或效率低下并不重要。我知道必须有更好的方法来做到这一点;请原谅我对可能是一个简单解决方案的事情一无所知。

【问题讨论】:

    标签: r list nested-loops lapply


    【解决方案1】:

    我认为!(%in%) 可以解决问题:

    SpecificSpecies <- data.frame(
      Species = c("S cerevisiae", "Daucus carota"),
      stringsAsFactors = FALSE
    )
    
    SCR <- data.frame(
      MESH_HEADINGS = c("tetracycline CMT-3", "zrg17 protein", "S cerevisiae", 
                        "EP4 glycoprotein", "Daucus carota"),
      stringsAsFactors = FALSE
    )
    
    
    SCR[!(SCR$MESH_HEADINGS %in% SpecificSpecies$Species), , drop = FALSE]
    #        MESH_HEADINGS
    # 1 tetracycline CMT-3
    # 2      zrg17 protein
    # 4   EP4 glycoprotein
    

    , , drop = ... 不是错字。第一个 , 确保返回所有列/变量。第二个, drop = FALSE 确保返回的结果仍然是一个数据帧。

    更正

    好的,我刚刚注意到您正在寻找 grep 和 Species。以下代码应该可以工作:

    SpecificSpecies <- data.frame(
      Species = c("S cerevisiae", "Daucus carota"),
      stringsAsFactors = FALSE
    )
    
    SCR <- data.frame(
      MESH_HEADINGS = c("tetracycline CMT-3",
                        "zrg17 protein, S cerevisiae", 
                        "EP4 glycoprotein, Daucus carota"),
      stringsAsFactors = FALSE
    )
    
    matching <- lapply(SpecificSpecies$Species, function(x) {
      grep(x, SCR$MESH_HEADINGS)
    })
    
    SCR[-(unlist(matching)), ]
    #        MESH_HEADINGS
    # 1 tetracycline CMT-3
    

    lapply() 使用匿名函数来识别模式匹配。它遍历每个物种并将其与每个SCR$MESH_HEADINGS 项目进行比较。它返回匹配索引的列表。

    在我们首先 unlisted 匹配的索引以使其与子集函数兼容之后,子集 ([]) 只需删除匹配的索引 (-)。

    【讨论】:

    • 不,恐怕不会。这些逗号不是分隔符,它们是原始字符串的一部分。也就是说,一些条目采用“蛋白质名称,物种名称”的形式。我需要使用 grep 或 regex 或类似的东西来提供匹配,因为该物种只会匹配 SCR$MESH_HEADING 的一部分。
    • 感谢您的帮助!两件事情。首先,您的示例对我有用,但是当我尝试使用我的实际数据时失败了。我得到一个 0 列表,然后在 unlist 上得到一个空表。知道为什么吗?其次,当我进行子集化时,我需要来自 SCR 的整个记录​​,而不仅仅是 MESH_HEADING。有没有一种简单的方法可以让它返回整行?
    • 它应该已经做这些事情了。您可以通过编辑您的问题发布数据框的子集,例如前 20 行左右。使用dput()。请参阅此帖子寻求帮助:stackoverflow.com/questions/5963269/…
    • @NotMyJob 对不起,我忘了@ 提到你:你能添加一些示例数据(见我之前的评论)。我们会让它工作的!
    【解决方案2】:

    主要思想:

    在 SpecificSpecies 上执行循环,因为它的行数较少。 由于 SCR 数据帧会减少,因此递归执行,因此循环每次处理的数据更少。

    一般来说,data.table 或 plyr 包可以提高性能。 这里是data.table的解决方案

        library(data.table)
    SpecificSpecies <- data.frame(Species = c("S cerevisiae", "Daucus carota"),stringsAsFactors = FALSE)
    SCR <- data.frame(MESH_HEADINGS = c("tetracycline CMT-3", "zrg17 protein, S cerevisiae","EP4 glycoprotein Daucus carota"),stringsAsFactors = FALSE)
    
    dt_temp <- data.table(SCR)
    for (species in SpecificSpecies$Species) {
      dt_temp <- dt_temp[!grepl(species,dt_temp$MESH_HEADINGS), ]
    }
    dt_result <- dt_temp
    dt_result
    

    【讨论】:

    • @NotMyJob 它的工作速度和你想要的一样快吗?可以标记为已解决吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 2013-08-23
    • 2018-06-06
    • 2017-09-03
    • 2015-06-29
    • 2018-04-15
    • 2022-12-31
    相关资源
    最近更新 更多