The support.bioconductor.org editor has been updated to markdown! Please see more info at: Tutorial: Updated Support Site Editor

Question: mclapply to loop over a GRangesList object
1
gravatar for foehn
16 days ago by
foehn30
foehn30 wrote:

Hello,

I'm trying to speed up lapply applied to a GRangesList object by replacing it with mclapply.

library(EnsDb.Hsapiens.v86)
GRsList <- exonsBy(EnsDb.Hsapiens.v86, by = "tx")
# the goal
res <- lapply(GRsList, FUN = gaps) 
# Here `gaps` is just for an example.

When I switch to mclapply, the code does not run faster at all

res <- mclapply(GRsList, FUN = gaps, mc.cores = 4) 

Careful inspection shows that inside mclapply, much of the time is spent on converting GRangesList to list.

GRsList <- as(GRsList, "list") # takes forever

Therefore I'm curious about how to convert GRsList to list, or simply how to make mclapply work with large GRangesList objects.

Thanks,

ADD COMMENTlink modified 15 days ago • written 16 days ago by foehn30
Answer: mclapply to loop over a GRangesList object
1
gravatar for Martin Morgan
16 days ago by
Martin Morgan ♦♦ 22k
United States
Martin Morgan ♦♦ 22k wrote:

Depending on what your goal is, a fast approach is to 'unlist-apply-relist'

gr = unlist(grl)
gr$foo = ...
relist(gr, grl)

Probably describing what you would like to do, in not too much detail, would lead to a more helpful answer.

ADD COMMENTlink written 16 days ago by Martin Morgan ♦♦ 22k

Thanks @Martin. My goal is to get introns from each transcript, that is what FUN in lapply does. Any suggestions?

ADD REPLYlink written 16 days ago by foehn30

Then you're looking for GenomicFeatures::intronsByTranscript()!

ADD REPLYlink written 16 days ago by Martin Morgan ♦♦ 22k

But GenomicFeatures::intronsByTranscript() does not work for EnsDb.Hspaiens.v86 which is from ensembldb...

ADD REPLYlink written 16 days ago by foehn30
1

intronsByTranscript() should probably be non-generic, as it should really just rely on functions in the "TxDb" API. But anyway, if you look at selectMethod(intronsByTranscript, "TxDb"), you will see the basic pattern for achieving what you want with ensembldb objects.

ADD REPLYlink written 16 days ago by Michael Lawrence10k

That's a good idea. For each transcript, intronsByTranscript uses psetdiff to find regions complementary to the exons and psetdiff is very fast.

ADD REPLYlink written 16 days ago by foehn30
Answer: mclapply to loop over a GRangesList object
0
gravatar for foehn
16 days ago by
foehn30
foehn30 wrote:

so, if the goal is to get introns per transcript, thanks to @martin's suggestion, we can use the method under the hood of intronsByTranscript:

exonsByTx <- exonsBy(EnsDb.Hsapiens.v86, "tx")
tx <- transcripts(EnsDb.Hsapiens.v86)
tx <- tx[match(names(exonsByTx), mcols(tx)[, "tx_id"])]
intronsByTx <- psetdiff(tx, exonsByTx)

Back to my original question, however, this method is not so generalizable and does not fit other user defined FUN in lapply. I'm still open to more versatile solutions.

ADD COMMENTlink written 16 days ago by foehn30

The infrastructure includes a good number of utilities for common use cases. Combined with the pattern Martin mentions above, the need for an actual lapply() is very rare. We've optimized lapply() to a reasonable extent, but the bottom line is that decompressing the GRangesList into an actual list is going to be expensive.

ADD REPLYlink written 16 days ago by Michael Lawrence10k

Thanks for the explanation.

ADD REPLYlink written 15 days ago by foehn30
Answer: mclapply to loop over a GRangesList object
0
gravatar for foehn
15 days ago by
foehn30
foehn30 wrote:

With regard to the original goal, one workaround is to create an external list to index the GRangesList:

index <- seq_along(GRsList)
res <- mclapply(index, FUN = function(i) gaps(GRsList[[i]]), mc.cores = 4)

Here gaps can be any other procedures applied to a GRanges object.

ADD COMMENTlink written 15 days ago by foehn30

I don't think that's any faster than

mclapply(GRsList, gaps, mc.cores = 4)

? The 'cost' is in creating a GRanges() for each element of the list, the cost is paid either internally by lapply() or explicitly by GRsList[[i]], and either way distributed across cores.

The 'Bioconductor' way would use BiocParallel::bplapply(), which would mean that the code would work on Windows (where mclapply() is not available) and potentially with other back-ends like a cluster (obviously for more complicated FUNs).

ADD REPLYlink modified 15 days ago • written 15 days ago by Martin Morgan ♦♦ 22k

I understand what you mean, and I agree there should be no fundamental difference. As mentioned before, the first step of mclapply is to convert GRangesList to list, which is time consuming and runs with only one core. Using an external index will avoid this step but distribute the cost to multiple cores, hence in total the running time can be reduced. This is true at least from my test.

ADD REPLYlink written 15 days ago by foehn30
Please log in to add an answer.

Help
Access

Use of this site constitutes acceptance of our User Agreement and Privacy Policy.
Powered by Biostar version 16.09
Traffic: 374 users visited in the last hour