繁体   English   中英

在 R 中分组后查找两个数据框之间的重叠范围

[英]Find overlapping ranges between two data frames after grouping in R

我有两个看起来像这样的大数据框:

df1 <- tibble(chrom=c(1,1,1,2,2,2),
              start=c(100,200,300,100,200,300),
              end=c(150,250,350,120,220,320))

df2 <- tibble(chrom=c(1,1,1,2,2,2),
              start2=c(100,50,280,100,10,200),
              end2=c(125,100,320,115,15,350))

df1
#> # A tibble: 6 × 3
#>   chrom start   end
#>   <dbl> <dbl> <dbl>
#> 1     1   100   150
#> 2     1   200   250
#> 3     1   300   350
#> 4     2   100   120
#> 5     2   200   220
#> 6     2   300   320
df2
#> # A tibble: 6 × 3
#>   chrom start2  end2
#>   <dbl>  <dbl> <dbl>
#> 1     1    100   125
#> 2     1     50   100
#> 3     1    280   320
#> 4     2    100   115
#> 5     2     10    15
#> 6     2    200   350

创建于 2023-01-09,使用reprex v2.0.2

找到 df2 的哪个范围 [start2-end2] 与 df1 的范围 [start-end] 重叠。 理想的 output 应该是这样的,但这不是必需的。 大多数情况下,我想要重叠范围的坐标。


#> # A tibble: 6 × 8
#>   chrom start   end start2  end2 overlap overlap_start overlap_end
#>   <dbl> <dbl> <dbl>  <dbl> <dbl> <chr>   <chr>         <chr>      
#> 1     1   100   150    100   125 yes     100           125        
#> 2     1   200   250     50   100 no      <NA>          <NA>       
#> 3     1   300   350    280   320 yes     300           320        
#> 4     2   100   120    100   115 yes     100           115        
#> 5     2   200   220     10    15 no      <NA>          <NA>       
#> 6     2   300   320    200   350 yes     200,220       300,320

创建于 2023-01-09,使用reprex v2.0.2

,请注意,在最后一行,范围 200-350 已经与 df1[200-220. 300-320]。

我相信您正在寻找这样的东西?

我认为没有必要在这里总结,因此您将获得 df2 范围 200-350 的两个结果。

library(data.table)
library(matrixStats)
# set to data.table format
setDT(df1); setDT(df2)
# perform join
ans <- df1[df2, .(chrom, 
                  start = x.start, end = x.end, 
                  start2 = i.start2, end2 = i.end2), 
           on = .(chrom, start < end2, end > start2),
           nomatch = NA]

# calculate new columns
ans[, overlap_start := rowMaxs(as.matrix(.SD)), .SDcols = c("start", "start2")]
ans[, overlap_end := rowMins(as.matrix(.SD)), .SDcols = c("end", "end2")]

#    chrom start end start2 end2 overlap_start overlap_end
# 1:     1   100 150    100  125           100         125
# 2:     1    NA  NA     50  100            NA          NA
# 3:     1   300 350    280  320           280         320
# 4:     2   100 120    100  115           100         115
# 5:     2    NA  NA     10   15            NA          NA
# 6:     2   200 220    200  350           200         220
# 7:     2   300 320    200  350           200         320

我的建议是使用 Bioconductor package GenomicRanges ,它可以使用最佳数据结构来查找区间重叠。

library(GenomicRanges)

df1 <- tibble(chrom=c(1,1,1,2,2,2),
              start=c(100,200,300,100,200,300),
              end=c(150,250,350,120,220,320))

df2 <- tibble(chrom=c(1,1,1,2,2,2),
              start2=c(100,50,280,100,10,200),
              end2=c(125,100,320,115,15,350))


overlaps <- findOverlapPairs(makeGRangesFromDataFrame(df1),
                             makeGRangesFromDataFrame(df2,
                                                      end.field = "end2",
                                                      start.field = "start2"))


> overlaps
Pairs object with 6 pairs and 0 metadata columns:
          first    second
      <GRanges> <GRanges>
  [1] 1:100-150  1:50-100
  [2] 1:100-150 1:100-125
  [3] 1:300-350 1:280-320
  [4] 2:100-120 2:100-115
  [5] 2:200-220 2:200-350
  [6] 2:300-320 2:200-350

mapply(as.data.frame,
       list(S4Vectors::first(overlaps),
            S4Vectors::second(overlaps)),
       SIMPLIFY = FALSE) |>
    do.call(what = `cbind`)

  seqnames start end width strand seqnames start end width strand
1        1   100 150    51      *        1    50 100    51      *
2        1   100 150    51      *        1   100 125    26      *
3        1   300 350    51      *        1   280 320    41      *
4        2   100 120    21      *        2   100 115    16      *
5        2   200 220    21      *        2   200 350   151      *
6        2   300 320    21      *        2   200 350   151      *


更长的“整洁风格”版本:

library(dplyr)

df1 |>
  left_join(df2, by = 'chrom') |>
  rowwise() |>
  mutate(range1 = list(start:end),
         range2 = list(start2:end2),
         intersect = list(intersect(start:end, start2:end2)),
         overlap = c('no', 'yes')[1 + sign(length(intersect))],
         overlap_start = ifelse(length(intersect), min(intersect), NA),
         overlap_end = ifelse(length(intersect), max(intersect), NA),
         ) |>
  group_by(paste(start2, end2)) |>
  summarise(across(chrom : end2),
            overlap,
            across(starts_with('overlap_'),
                   ~ paste(na.omit(.x), collapse = ','))
            ) |>
  ungroup() |>
  select(chrom:overlap_end)
# A tibble: 18 x 8
   chrom start   end start2  end2 overlap overlap_start overlap_end
   <dbl> <dbl> <dbl>  <dbl> <dbl> <chr>   <chr>         <chr>      
 1     2   100   120     10    15 no      ""            ""         
 2     2   200   220     10    15 no      ""            ""         
 3     2   300   320     10    15 no      ""            ""         
 4     2   100   120    100   115 yes     "100"         "115"      
 5     2   200   220    100   115 no      "100"         "115"      
 6     2   300   320    100   115 no      "100"         "115"      
 7     1   100   150    100   125 yes     "100"         "125"      
 8     1   200   250    100   125 no      "100"         "125"      
 9     1   300   350    100   125 no      "100"         "125"      
10     2   100   120    200   350 no      "200,300"     "220,320" 
# ...

要获得多个重叠的数字向量而不是逗号分隔的字符串,请改为使用以下片段进行总结:

## ...
    across(starts_with('overlap_'),
           ~ list(c(na.omit(.x)))
           )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM