【问题标题】:How to bypass a nested for loop?如何绕过嵌套的 for 循环?
【发布时间】:2018-03-29 06:09:41
【问题描述】:

所以情况是这样的: 我基本上有一个数据框,其中包含大约 100,000 行数据。我对特定的数据列 POS 感兴趣,我想检查 POS 的值是否介于另一个数据框 Start 和 End 的两个值之间,并跟踪其中有多少实例。

例如,在我的第一个数据框中,我有类似

ID POS  
A   20  
B   533  
C   600 

在我的其他数据框中,我有类似的东西

START      END  
123        150  
489        552  
590        600  

我想知道 POS 中有多少项目在任何 START-END 范围内。所以在这种情况下,有 2 个项目。另外,如果可能的话,我也可以获取在 Start 和 End 之间带有 POS 的 ID 吗?

如何在不使用嵌套 for 循环的情况下执行此操作?

【问题讨论】:

标签: r loops


【解决方案1】:

这是一个相当普遍的问题,可能发生在数据库的上下文中。这是使用sqldf的解决方案:

library(sqldf)

query <- "SELECT POS, ID FROM df1 INNER JOIN df2 "
query <- paste0(query, "ON df1.POS BETWEEN df2.START AND df2.END")
sqldf(query)

如果您的第二个数据框中的范围可能重叠,则上述查询可能会为给定的POS 值返回多个结果。在这种情况下,请将SELECT POS 替换为SELECT DISTINCT POS

【讨论】:

  • 这是一个有趣的包,以前从未见过!是否可以使用这种方法获取POS值在Start和End之间的ID?
  • @AlexJohanssen 是的,只需将ID 添加到选择列表中即可。
  • 抱歉,还有一个问题。假设在第二个 df 中我也想包含一个 ID 字段。我该怎么做呢?
  • 只需将您需要的任何内容添加到SELECT 列表中,例如STARTEND。如果这两个表的列名恰好相同,那么您必须更新我的查询以使用别名。做起来不难,但也许你不需要它。
【解决方案2】:

我们可以对data.table使用非等连接

library(data.table)
setDT(df1)[df2, on = .(POS > START, POS <= END)][, sum(!is.na(ID))]
#[1] 2

【讨论】:

  • 谢谢!是否可以使用这种方法获取POS值在Start和End之间的ID?
  • @AlexJohanssen 你只需要setDT(df1)[df2, on = .(POS &gt; START, POS &lt;= END)][!is.na(ID)]$ID#[1] "B" "C"
【解决方案3】:

我们可以在base-R 中使用mapply 来实现同样的效果:

df1[mapply(function(x)any(x >= df2$START & x <= df2$END),df1$POS),]
#  ID POS
#2  B 533
#3  C 600

数据

df1 <- read.table(text = 
"ID POS  
A   20  
B   533  
C   600", header = T)


df2 <- read.table(text = 
"START      END  
123        150  
489        552  
590        600", header = TRUE)

【讨论】:

    【解决方案4】:

    数据框:main

    ID POS  
    A   20  
    B   533  
    C   600 
    

    数据框:ran

    START   END  
    123     150  
    489     552  
    590     600
    

    一个简单的sapply 应该足以满足您的用例:

    sapply(main$POS, function(x) { sum(x>=ran$START & x<=ran$END) })
    

    将返回:

    [1] 0 1 1
    

    您可以将其绑定回 main 数据框中的新列:

    main$Count <- sapply(main$POS, function(x) { sum(x>=ran$START & x<=ran$END) }))
    
      ID POS count
    1  A  20     0
    2  B 533     1
    3  C 600     1
    

    这也适用于重叠范围。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      相关资源
      最近更新 更多