4

I have two tables where each of them including range of numbers. one table is subdivision of the other. I want to create binary column in the first table which shows in which range they are overlapped.

for example:

df1:
start1   end1
 1       6
 6       8
 9       12
 13      15
 15      19
 19      20

df2:
start2   end2
 2        4
 9        11
 14       18

result: the result is the first table with column that shows if the overlap exists.

  start1   end1   overlap
     1       6       1
     6       8       0
     9       12      1
     13      15      1
     15      19      1
     19      20      0

thanks.

Cina
  • 9,759
  • 4
  • 20
  • 36

4 Answers4

7

You may also try foverlaps from data.table

library(data.table)
setkey(setDT(df1), start1, end1)
setkey(setDT(df2), start2, end2)
df1[,overlap:=foverlaps(df1, df2, which=TRUE)[, !is.na(yid),]+0]
df1
#   start1 end1 overlap
#1:      1    6       1
#2:      6    8       0
#3:      9   12       1
#4:     13   15       1
#5:     15   19       1
#6:     19   20       0
akrun
  • 874,273
  • 37
  • 540
  • 662
3

With IRanges

library(IRanges)
ir1 = with(df1, IRanges(start1, end1))
ir2 = with(df2, IRanges(start2, end2))
df1$overlap = countOverlaps(ir1, ir2) != 0

If on the off chance this is genomic data, the GenomicRanges packages is appropriate.

Martin Morgan
  • 45,935
  • 7
  • 84
  • 112
  • yes it is. I am working on genomic data to detect specific binding sites. The package is really helpful. thanks sir – Cina Nov 14 '14 at 06:24
1

Here's an approach based on generating sequences:

nums <- unlist(apply(df2, 1, Reduce, f = seq))

df1$overlap <- as.integer(apply(df1, 1, function(x) any(seq(x[1], x[2]) %in% nums)))
#   start1 end1 overlap
# 1      1    6       1
# 2      6    8       0
# 3      9   12       1
# 4     13   15       1
# 5     15   19       1
# 6     19   20       0
Sven Hohenstein
  • 80,497
  • 17
  • 145
  • 168
  • is some cases it doesn't work; if df2 containing elements which are not in df1. the error is: `Error in seq(x[1], x[2]) %in% nums : error in evaluating the argument 'x' in selecting a method for function '%in%': Error in seq.default(x[1], x[2]) : 'from' cannot be NA, NaN or infinite ` – Cina Nov 25 '14 at 07:08
1

You can use the ivs package, which is a package specifically about interval vectors. iv_overlaps() returns a logical vector that specifies if each interval of the column from df1 overlaps any interval from df2.

library(dplyr)
library(ivs)

df1 <- tribble(
  ~start1, ~end1,
  1,       6,
  6,       8,
  9,       12,
  13,      15,
  15,      19,
  19,      20
)

df2 <- tribble(
  ~start2,   ~end2,
  2,        4,
  9,        11,
  14,       18
)

df1 <- mutate(df1, range1 = iv(start1, end1), .keep = "unused")
df2 <- mutate(df2, range2 = iv(start2, end2), .keep = "unused")

df1 %>%
  mutate(any_overlap = iv_overlaps(range1, df2$range2))
#> # A tibble: 6 × 2
#>      range1 any_overlap
#>   <iv<dbl>> <lgl>      
#> 1    [1, 6) TRUE       
#> 2    [6, 8) FALSE      
#> 3   [9, 12) TRUE       
#> 4  [13, 15) TRUE       
#> 5  [15, 19) TRUE       
#> 6  [19, 20) FALSE
Davis Vaughan
  • 2,780
  • 9
  • 19