I have a dataset (mydata
) that contains multiple columns which could fit inside ranges that are stored in another dataset (mycomparison
).
I would like to join mycomparison
to mydata
where the mydata
values are within the ranges in mycomparison
.
MWE
library(data.table)
mydata<-data.table(
id=1:5,
val1=seq(10000, 50000, by=10000),
val2=floor(rnorm(5,mean=400,sd=100)),
val3=rnorm(5,mean=.7,sd=.1)
)
mycomparison<-data.table(
Name=LETTERS[1:3],
minval1=c(0,30000,10000),
maxval1=c(50000,80000,30000),
minval2=c(300,400,300),
maxval2=c(800,800,800),
minval3=c(0,.5,.2),
maxval3=c(1,.9,.8),
correspondingval=c(.1,.2,.3)
)
Desired Output
> mydata.withmatches
id val1 val2 val3 Name minval1 maxval1 minval2 maxval2 minval3 maxval3 correspondingval
1: 1 10000 387 0.4844319 A 0 50000 300 800 0 1 0.1
2: 2 20000 425 0.7856313 NA NA NA NA NA NA NA NA
3: 3 30000 324 0.8063969 NA NA NA NA NA NA NA NA
4: 4 40000 263 0.5590113 NA NA NA NA NA NA NA NA
5: 5 50000 187 0.8764396 NA NA NA NA NA NA NA NA
Current solution
This feels/is very clunky and involves cross-joining the data (using optiRum::CJ.dt
), doing a big logical check, and then reassembling the data.
library(optiRum)
workingdt<-CJ.dt(mydata,mycomparison)
matched<-workingdt[val1>=minval1 &
val1<=maxval1 &
val2>=minval2 &
val2<=maxval2 &
val3>=minval3 &
val3<=maxval3][which.min(correspondingval)]
notmatched<-mydata[id!= matched[,id]]
all<-list(matched,notmatched)
mydata.withmatches<- rbindlist(all, fill=TRUE, use.names=TRUE)
Looking for a better solution - UPDATED
I'm aware of foverlaps
but it will work on a single interval, not on many ranges like in this instance.
I'm hoping for a less clunky and more elegant solution.