Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R optimization: How can I avoid a for loop in this situation?

I'm trying to do a simple genomic track intersection in R, and running into major performance problems, probably related to my use of for loops.

In this situation, I have pre-defined windows at intervals of 100bp and I'm trying to calculate how much of each window is covered by the annotations in mylist. Graphically, it looks something like this:

          0    100   200    300    400   500   600  
windows: |-----|-----|-----|-----|-----|-----|

mylist:    |-|   |-----------|

So I wrote some code to do just that, but it's fairly slow and has become a bottleneck in my code:

##window for each 100-bp segment    
windows <- numeric(6)

##second track
mylist = vector("list")
mylist[[1]] = c(1,20)
mylist[[2]] = c(120,320)


##do the intersection
for(i in 1:length(mylist)){
  st <- floor(mylist[[i]][1]/100)+1
  sp <- floor(mylist[[i]][2]/100)+1
  for(j in st:sp){       
    b <- max((j-1)*100, mylist[[i]][1])
    e <- min(j*100, mylist[[i]][2])
    windows[j] <- windows[j] + e - b + 1
  }
}

print(windows)
[1]  20  81 101  21   0   0

Naturally, this is being used on data sets that are much larger than the example I provide here. Through some profiling, I can see that the bottleneck is in the for loops, but my clumsy attempt to vectorize it using *apply functions resulted in code that runs an order of magnitude more slowly.

I suppose I could write something in C, but I'd like to avoid that if possible. Can anyone suggest another approach that will speed this calculation up?

like image 319
chrisamiller Avatar asked Mar 25 '10 17:03

chrisamiller


People also ask

Should you avoid for loops in R?

For that reason, it might make sense for you to avoid for-loops and to use functions such as lapply instead. This might speed up the R syntax and can save a lot of computational power! The next example explains how to use the lapply function in R.

How do I stop a loop from running in R?

A break statement is used inside a loop (repeat, for, while) to stop the iterations and flow the control outside of the loop.

Which in built functions in R can be used to optimize tasks which require looping?

The sapply() function behaves similarly to lapply() ; the only real difference is in the return value. sapply() will try to simplify the result of lapply() if possible.


2 Answers

The "Right" thing to do is to use the bioconductor IRanges package, which uses an IntervalTree data structure to represent these ranges.

Having both of your objects in their own IRanges objects, you would then use the findOverlaps function to win.

Get it here:

http://www.bioconductor.org/packages/release/bioc/html/IRanges.html

By the by, the internals of the package are written in C, so its super fast.

EDIT

On second thought, it's not as much of a slam-dunk as I'm suggesting (a one liner), but you should definitely start using this library if you're working at all with genomic intervals (or other types) ... you'll likely need to do some set operations and stuff. Sorry, don't have time to provide the exact answer, though.

I just thought it's important to point this library out to you.

like image 90
Steve Lianoglou Avatar answered Oct 28 '22 17:10

Steve Lianoglou


So I'm not entirely sure why the third and fourth windows aren't 100 and 20 because that would make more sense to me. Here's a one liner for that behavior:

Reduce('+', lapply(mylist, function(x) hist(x[1]:x[2], breaks = (0:6) * 100, plot = F)$counts)) 

Note that you need to specify the upper bound in breaks, but it shouldn't be hard to make another pass to get it if you don't know it in advance.

like image 4
Jonathan Chang Avatar answered Oct 28 '22 17:10

Jonathan Chang