背景:我将提供此代码的应用背景和编程背景。希望对您有帮助。我从事基因组计算工作。是的-另一位伪装成计算机科学家的生物学家。我正在编写一个脚本,该脚本将使我能够按人类基因组中的每个位置整合一堆数据集。这将转换为一个超过30亿行乘12列的数据框。作为测试数据集,我正在使用酵母基因组构建我的分析管道,这将生成一个大约2500万行和12列的数据框。
问题:我当前的代码运行正常,但运行缓慢。例如,我在45分钟前启动了管道,整个过程大约是酵母基因组的1/3。这意味着完成一个酵母样本可能需要135分钟,或者一个人类样本需要270小时……现在,将其乘以我准备分析的90个人类样本,就可以看到我的问题了。我需要加快速度。我将并行化它,但是即使那样,我仍然认为它本身的代码太笨拙。我需要帮助,以使我现有的功能大大加快。请不要告诉我,我需要对其进行并行化(这将获得否决权)。
示例数据:
chrom <- c("chr1", "chr1", "chr1", "chr1")
start <- c("0","1","2","6")
stop <- c("1","2","6","7")
sequence <- c("a", "t", "tcag", "a")
seqData <- data.frame(chrom, start, stop, sequence)
示例输出:
chrom_out <- c("chr1", "chr1", "chr1", "chr1", "chr1", "chr1", "chr1")
start_out <- c("0", "1", "2", "3", "4", "5", "6")
stop_out <- c("1", "2", "3", "4", "5", "6", "7")
sequence_out <- c("a", "t", "t", "c", "a", "g", "a")
out_seqdata <- data.frame(chrom_out, start_out, stop_out, sequence_out)
当前代码:
library(dplyr)
library(stringi)
library(stringr)
wl = function(x){
length<- stri_length(x["sequence"])
if(length ==1){
tmpseq<- x["sequence"]
tmpstart <- as.numeric(x["start"])
tmpstop <- as.numeric(x["stop"])
tmpchrom <- x["chrom"]
tmpdf <- data.frame(tmpseq, tmpstart, tmpstop, tmpchrom)
colnames(tmpdf)<- c("tmpseq", "tmpstart", "tmpstop", "tmpchrom")
print(tmpdf)
}else{
tmpseq<- strsplit(x["sequence"], "(?<=.{1})", perl = TRUE)
tmpstart <- as.numeric(x["start"])+(1:length-1)
tmpstop<- as.numeric(x["start"])+(1:length)
tmpdf <- data.frame(tmpseq, tmpstart, tmpstop)
tmpdf$tmpchrom <- x["chrom"]
colnames(tmpdf)<- c("tmpseq", "tmpstart", "tmpstop", "tmpchrom")
print(tmpdf)
}
}
代码说明:我使用apply遍历数据帧的每一行。数据框是坐标列表和这些坐标的基因组序列。 Chrom =染色体,start =染色体上的起始位置,stop =终止位置,序列为实际序列。数据当前为压缩格式,以第三行数据为例。我想扩展此数据,以便每个基因组字母成为其自己的行,然后适当调整坐标范围。功能wl(代表宽到长)执行此操作。它首先确定序列的字符串长度。如果长度等于1,则将其作为数据帧返回该行,而无需进一步操作。否则,它将字符串分解为单个字符,确定每个字符的坐标,然后返回此数据帧。结果是一个数据帧列表,然后将它们重新绑定在一起,生成示例输出数据。
我需要的:我将对基因组进行分块,创建一个列表,从而使我可以并行化该列表。这些块将导致一系列大约2500万行的数据帧。我也将并行化多个样本。并行化中的并行化……听起来像是使集群崩溃的好方法。我知道该怎么做(都写这段代码并使集群崩溃)。我需要帮助的是使实际功能更快。使用我当前的功能,2500万行仍需要很长时间来处理。任何想法将不胜感激。请编辑我的功能或推荐一种新方法-欢迎提出所有想法。除了增加功能之外,我不知道更快的方法。
答案 0 :(得分:4)
您可以矢量化所有操作:
# Generate vector of start positions
# Goes from 0 (minimal position in given data) to maximum base position in chromosome
foo <- 0:max(as.numeric(as.character(seqData$start)))
# Split sequence into a character vector
bar <- unlist(strsplit(as.character(seqData$sequence), ""))
# Generate final data frame
data.frame(start = foo, end = foo + 1, seq = bar)
# start end seq
# 1 0 1 a
# 2 1 2 t
# 3 2 3 t
# 4 3 4 c
# 5 4 5 a
# 6 5 6 g
# 7 6 7 a
您可以使用此代码一次遍历一条染色体。
自定义函数和易于并行化的foreach
循环可能看起来像这样:
wl <- function(data, chr) {
startPos <- 0:max(as.numeric(as.character(data$start)))
nucs <- unlist(strsplit(as.character(data$sequence), ""))
data.frame(chr, start = startPos, end = startPos + 1, seq = nucs)
}
library(foreach)
# use dopar for parallel computations
foreach(i = unique(seqData$chr), .combine = rbind) %do% {
wl(subset(seqData, chrom == i), i)
}
PS:我不会从不使用基因组坐标作为特征向量。另外,创建end
列只是浪费空间,因为您知道它在start
中的位置为1。