在 R 中运行循环非常缓慢

时间:2021-06-01 14:31:33

标签: r merge tidyverse

我有一个脚本可以计算拷贝数变异,并将数据保存到一个名为“resultCNV.txt”的现有文件中,该文件基于第一列信息。 这是我的脚本

setwd("./Data")
library(GenomicRanges)
library(dplyr)
library("scales")
require(tidyverse)
#Create annotation or refrence table
genes <- read.table("./Basefile/genes.txt", sep="\t", stringsAsFactors=FALSE, header=TRUE)
genes$chromosome_name <- gsub('X', '23', genes$chromosome_name)
genes$chromosome_name <- gsub('Y', '24', genes$chromosome_name)
colnames(genes) <- c("GeneSymbol","Chr","Start","End")
genes_GR <- makeGRangesFromDataFrame(genes,keep.extra.columns = TRUE)
#File need to be analyzed (3 step: preprocessing, comparison with reference or annotation and post-porcessing)
for(i in 1:36){
  df<- read.table(paste0("BRCA", i, ".txt"), sep="\t", stringsAsFactors=FALSE, header=TRUE)
  df$Chromosome <- gsub('X', '23', df$Chromosome)
  df$Chromosome <- gsub('Y', '24', df$Chromosome)
  colnames(df) <- c("Barcode", "Chr", "Start", "End", "extra1", "extra2")
  cnv <-  makeGRangesFromDataFrame(df, keep.extra.columns = TRUE)
  hits <- findOverlaps(genes_GR, cnv, type="within")
  df_ann <- cbind(df[subjectHits(hits),],genes[queryHits(hits),])
  df_ann <- unique(df_ann)
  df_ann <- df_ann[ , c("GeneSymbol", "Chr", "extra2")]
  colnames(df_ann) <- c("Ensembl_ID","Chr","Seg_value")
  df_ann$Seg_value2 <- abs(df_ann$Seg_value)
  df_ann$Seg_value2 = 2^df_ann$Seg_value2
  df_ann$Seg_value2 = df_ann[, 4] - 1
  df_ann$Seg_value2 = df_ann[, 4] * 2
  df_ann$Seg_value2 <- with(df_ann, sign(Seg_value) * Seg_value2)
  df_ann <- df_ann[ , c("Ensembl_ID", "Seg_value")]
  df_ann$Seg_value <- rescale(df_ann$Seg_value, to = c(-1, 1))
  df_ann1 <- read.table("/Basefile/genesforcomp.txt", sep="\t", stringsAsFactors=FALSE, header=TRUE)
  df <- rbind.data.frame(df_ann, df_ann1)
  df <- df[!duplicated(df$Ensembl_ID),]
  #saving the results into existing file based on first column values
  df1 <- read.delim("resultCNV.txt", check.names=FALSE, stringsAsFactors=FALSE)
  lst <- list(data.frame(df1), data.frame(df))
  df2 <- reduce(lst, full_join, by = "Ensembl_ID") %>% replace(., is.na(.), 0);
  write.table(df2, file="resultCNV.txt", quote = F, sep = "\t", row.names = F)
}

这是我用于测试 Link 的数据。它有两个文件夹:base 文件夹:用于一次读取和 Data:用于数据。

在最后 4 行中,我使用 tidyverse 的 full_join 函数,根据第一列值 (Ensembl_ID) 将分析的列添加到最后保存的输出中。我每次运行大约 200 个文件,它需要将近 2 个小时,而运行 100 个文件只需要 30 分钟(时间与循环次数中的双曲线曲线)。每次循环,输出文件大小减少到原来的 900kb,然后随着每个循环增加,例如 5 mb 然后 11 mb,依此类推。

是否可以减少时间,即不读取上次保存的输出而仅根据第一列合并列? 任何关于如何循环脚本的建议或想法将不胜感激。

提前致谢!

2 个答案:

答案 0 :(得分:1)

当我认为我的循环太慢时,我会改用 apply 方法。在你的情况下,它会是这样的:

e = function(i){
  df<- read.table(paste0("BRCA", i, ".txt"), sep="\t", stringsAsFactors=FALSE, header=TRUE)
  df$Chromosome <- gsub('X', '23', df$Chromosome)
  df$Chromosome <- gsub('Y', '24', df$Chromosome)
  colnames(df) <- c("Barcode", "Chr", "Start", "End", "extra1", "extra2")
  cnv <-  makeGRangesFromDataFrame(df, keep.extra.columns = TRUE)
  hits <- findOverlaps(genes_GR, cnv, type="within")
  df_ann <- cbind(df[subjectHits(hits),],genes[queryHits(hits),])
  df_ann <- unique(df_ann)
  df_ann <- df_ann[ , c("GeneSymbol", "Chr", "extra2")]
  colnames(df_ann) <- c("Ensembl_ID","Chr","Seg_value")
  df_ann$Seg_value2 <- abs(df_ann$Seg_value)
  df_ann$Seg_value2 = 2^df_ann$Seg_value2
  df_ann$Seg_value2 = df_ann[, 4] - 1
  df_ann$Seg_value2 = df_ann[, 4] * 2
  df_ann$Seg_value2 <- with(df_ann, sign(Seg_value) * Seg_value2)
  df_ann <- df_ann[ , c("Ensembl_ID", "Seg_value")]
  df_ann$Seg_value <- rescale(df_ann$Seg_value, to = c(-1, 1))
  df_ann1 <- read.table("/home/sumit/Academic/DHR/TCGA/Gene List/Final1/genesbase.txt", sep="\t", stringsAsFactors=FALSE, header=TRUE)
  df <- rbind.data.frame(df_ann, df_ann1)
  df <- df[!duplicated(df$Ensembl_ID),]
  #saving the results into existing file based on first column values
  df1 <- read.delim("genesforcomp1", check.names=FALSE, stringsAsFactors=FALSE)
  lst <- list(data.frame(df1), data.frame(df))
  df2 <- reduce(lst, full_join, by = "Ensembl_ID") %>% replace(., is.na(.), 0);
  write.table(df2, file="genesforcomp1", quote = F, sep = "\t", row.names = F)
}

lapply(1:4376, e)

在我的许多分析中,这为我节省了大量时间,我希望它也适用于您。

小奖励,估计您可以使用 pbapply 包中的 lapply 代替 pblapply() 的时间。

希望对你有帮助

答案 1 :(得分:0)

read.table 和 write.table 或实际上 rbase read.delim 函数在每次迭代中覆盖输出文件。它获取所有数据,然后开始一个接一个地添加具有匹配第一列行的列,因此随着文件的增长,它需要越来越多的时间来读取和写入。理想情况下,它应该以大文件为基础,将较小的输出合并到与第一列匹配的大文件中。

data.table 库函数 data.table::fread 和 fwrite 在这种情况下很好,因为它不会覆盖,而是以较大的文件为基础,只粘贴具有匹配行的小文件。

data.table::fread / fwrite (27 sec) 的性能优于 readr (93 sec) 或 read.delim (145 sec)。我觉得可以接受。

相关问题