如何从两个 DataFrame 中提取基于两个条件匹配的行

how to extract rows which match based on two conditions from two dataframes

提问人:Rhea Bedi 提问时间:7/1/2023 更新时间:7/2/2023 访问量:47

问:

我有两个数据帧,一个是 snp 区域,另一个是 Hic 区域。

dput(hic_region[1:15,1:4])
structure(list(rf1 = c(57584944, 57584944, 57584944, 57584944, 
57584944, 57584944, 57584944, 57584944, 50263463, 5e+07, 50263463, 
50263463, 35172197, 35172197, 57584944), rt1 = c(57624944, 57624944, 
57624944, 57624944, 57624944, 57624944, 57624944, 57624944, 50303463, 
51423463, 50303463, 50303463, 35212197, 35212197, 57624944), 
    rf2 = c(1899354, 1899354, 1899354, 1899354, 1899354, 1579354, 
    1899354, 1899354, 1899354, 1779354, 1899354, 1899354, 1899354, 
    1899354, 1499354), rt2 = c(1939354, 1939354, 1939354, 1939354, 
    1939354, 1619354, 1939354, 1939354, 1939354, 1819354, 1939354, 
    1939354, 1939354, 1939354, 1539354)), row.names = c(NA, -15L
), class = c("tbl_df", "tbl", "data.frame"))
> dput(snp_region[1:10,1:6])
structure(list(Gene = c("ENSG00000132819", "ENSG00000101162", 
"ENSG00000132819", "ENSG00000101162", "ENSG00000101162", "ENSG00000101162", 
"ENSG00000101162", "ENSG00000101162", "ENSG00000101162", "ENSG00000101162"
), `Gene-Chr` = c(20, 20, 20, 20, 20, 20, 20, 20, 20, 20), `Gene-Pos` = c(55975426, 
57598009, 55975426, 57598009, 57598009, 57598009, 57598009, 57598009, 
57598009, 57598009), RsId = c("rs6084653", "rs156356", "rs1741314", 
"rs6136489", "rs4814776", "rs13042885", "rs4814779", "rs6045615", 
"rs11696739", "rs4618126"), `SNP-Chr` = c(20, 20, 20, 20, 20, 
20, 20, 20, 20, 20), `SNP-Pos` = c(4157072, 1819280, 4155193, 
1923734, 1921523, 1924707, 1923271, 1931582, 1600925, 1930885
)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"
))

我想将 snp 区域中存在的基因与从 rf1 到 rt1 的 hic 区域相匹配,如果它存在于这两个区域(rf1 和 rt1)之间,请选择该基因,然后使用 rf2 和 rt2 区域匹配 snp 区域的 snp 位置。 我写了一个代码,但它给了我重复的值。

snp <- data.frame()
for(i in 1:dim(snp_region)[1]){
  snp_pos <- snp_region$`SNP-Pos`[i]
  for(j in 1:dim(hic_region)[1]){
  if(snp_region$`Gene-Pos`[i] %in% seq(hic_region$rf1[j],hic_region$rt1[j],1)){
   hic_region1 <- hic_region[j,]
    if(snp_pos %in% seq(hic_region1$rf2,hic_region1$rt2,1)){
      preset <<- snp_region[i,]
    } 
  }
  }
  snp <- rbind(snp,preset)
}


dput(snp[1:5,1:6])
structure(list(Gene = c("ENSG00000131069", "ENSG00000131069", 
"ENSG00000131069", "ENSG00000101162", "ENSG00000101162"), `Gene-Chr` = c(20, 
20, 20, 20, 20), `Gene-Pos` = c(33487859, 33487859, 33487859, 
57598009, 57598009), RsId = c("rs4142441", "rs4142441", "rs4142441", 
"rs6136489", "rs4814776"), `SNP-Chr` = c(20, 20, 20, 20, 20), 
    `SNP-Pos` = c(42839620, 42839620, 42839620, 1923734, 1921523
    )), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"
))

如果我做错了什么,或者是否有更好的方法来运行两个条件来匹配两个数据帧的行,我想得到一些反馈。 谢谢。

r 数据帧 循环条件 语句 rbind

评论


答:

2赞 jkatam 7/1/2023 #1

请尝试以下代码,您将获得与snp_region

在这里你会得到 2flg

flg表示从 RF1 到 RT1 的 SNP 区域到 HIC 区域,如果它存在于这两个区域(RF1 和 RT1)之间

flg2表示使用 RF2 和 RT2 区域的 SNP 区域的 SNP 位置匹配。

library(tidyverse)

snp_region2 <- snp_region %>% mutate(row=row_number())

snp_region2 %>% cross_join(hic_region) %>% 
  mutate(flg=ifelse(between(`Gene-Pos`,rf1,rt1),1,NA),
         flg2=ifelse(flg==1 & between(`SNP-Pos`,rf2,rt2),1,NA)) %>% 
  group_by(row) %>% slice_head(n=1) %>% filter(!is.na(flg)|!is.na(flg2))

# output 

# A tibble: 8 × 13
# Groups:   row [8]
  Gene      `Gene-Chr` `Gene-Pos` RsId  `SNP-Chr` `SNP-Pos`   row    rf1    rt1    rf2
  <chr>          <dbl>      <dbl> <chr>     <dbl>     <dbl> <int>  <dbl>  <dbl>  <dbl>
1 ENSG0000…         20   57598009 rs15…        20   1819280     2 5.76e7 5.76e7 1.90e6
2 ENSG0000…         20   57598009 rs61…        20   1923734     4 5.76e7 5.76e7 1.90e6
3 ENSG0000…         20   57598009 rs48…        20   1921523     5 5.76e7 5.76e7 1.90e6
4 ENSG0000…         20   57598009 rs13…        20   1924707     6 5.76e7 5.76e7 1.90e6
5 ENSG0000…         20   57598009 rs48…        20   1923271     7 5.76e7 5.76e7 1.90e6
6 ENSG0000…         20   57598009 rs60…        20   1931582     8 5.76e7 5.76e7 1.90e6
7 ENSG0000…         20   57598009 rs11…        20   1600925     9 5.76e7 5.76e7 1.90e6
8 ENSG0000…         20   57598009 rs46…        20   1930885    10 5.76e7 5.76e7 1.90e6
# ℹ 3 more variables: rt2 <dbl>, flg <dbl>, flg2 <dbl>

评论

0赞 Till 7/1/2023
我喜欢这个解决方案!不错的应用程序。我认为您可以省略并简单地使用条件创建一个 ,这通常对下游任务更有用。喜欢:dplyr::between()ifelse()logicalflg=between(`Gene-Pos`, rf1, rt1)
0赞 jkatam 7/1/2023
我是一名SAS程序员,所以习惯于创建这样的标志变量。但我同意你的评论。谢谢
0赞 jkatam 7/2/2023
您选择的答案返回 7 行,我的答案返回 8 行,我很想知道哪个是正确的
0赞 Jamie 7/2/2023
@jkatam - 我相信 OP 希望包含该基因,如果并且在 rf/rt 变量的范围内。例如,对于同一行。在您的输出中,仅满足一半标准的基因。 匹配但不匹配。Gene-PosSNP-PosRsId == rs156356Gene-PosSNP-Pos
1赞 Jamie 7/1/2023 #2

这是使用 .此过程称为联接。data.tablenon-equi

在该部分中,您可以创建介于 和 AND 之间的逻辑。然后选择要包含在两个表中的列。onGene-Posrt1rf2SNP-Posrf2rt2

library(data.table)

setDT(hic_region)
setDT(snp_region)

matched_genes = unique(snp_region[
  hic_region, 
  on = .(`Gene-Pos` >= rf1, `Gene-Pos` <= rt1, `SNP-Pos` >= rf2, `SNP-Pos` <= rt2), 
  .(Gene, `Gene-Chr`, `Gene-Pos`=`x.Gene-Pos`, RsId, `SNP-Chr`, `SNP-Pos`=`x.SNP-Pos`, rf1, rt1, rf2, rt2), 
  nomatch = NULL
])

matched_genes
# Output

              Gene Gene-Chr Gene-Pos       RsId SNP-Chr SNP-Pos      rf1      rt1     rf2     rt2
1: ENSG00000101162       20 57598009  rs6136489      20 1923734 57584944 57624944 1899354 1939354
2: ENSG00000101162       20 57598009  rs4814776      20 1921523 57584944 57624944 1899354 1939354
3: ENSG00000101162       20 57598009 rs13042885      20 1924707 57584944 57624944 1899354 1939354
4: ENSG00000101162       20 57598009  rs4814779      20 1923271 57584944 57624944 1899354 1939354
5: ENSG00000101162       20 57598009  rs6045615      20 1931582 57584944 57624944 1899354 1939354
6: ENSG00000101162       20 57598009  rs4618126      20 1930885 57584944 57624944 1899354 1939354
7: ENSG00000101162       20 57598009 rs11696739      20 1600925 57584944 57624944 1579354 1619354