R代码运行得太慢,如何重写这段代码

时间:2014-03-14 02:00:22

标签: r loops bigdata

input.txt包含8000000行和4列。前两列是文本。最后两列是数字。第1列和第2列中的唯一符号(例如," c33")的数量不固定。第3列和第4列的值是在按"]"分割后第1列和第2列的唯一符号数。分别。 input.txt文件的每一行都是这样的:


c33]c21]c5]c7]c8]c9  TPS2]MIC17]ERG3]NNF1]CIS3]CWP2  6  6

<小时/> **期望的结果: enter image description here

row[ , ] represents characters like "c33 c21 c5 c7 c8 c9" or "TPS2 MIC17 ERG3 NNF1 CIS3 CWP2", | .| represents the number of characters, |c33 c21 c5 c7 c8 c9|=6

如果两行重叠(> = 0.6),则输出NO。将这两行写入文件。**

此代码如下,但运行速度太慢。

代码:

 library(compiler)
 enableJIT(3)
 data<-read.table("input.txt",header=FALSE)
 row<-8000000
for (i in 1:(row-1)){
    row11<-unlist(strsplit(as.character(data[i,1]),"]"))
     row12<-unlist(strsplit(as.character(data[i,2]),"]"))
    s1<-data[i,3]*data[i,4]
    zz<-file(paste("output",i,".txt",sep=""),"w")
   for (j in (i+1):row)
      { row21<-unlist(strsplit(as.character(data[j,1]),"]"))
        row22<-unlist(strsplit(as.character(data[j,2]),"]"))
        up<-length(intersect(row11,row21))*length(intersect(row12,row22))
        s2<-data[j,3]*data[j,4]
        down<-min(s1,s2)
       if ((up/down)>=0.6) cat(i,"\t",j,"\n",file=zz,append=TRUE)
      }
   close(zz)
}

运行结果: 每一行都可以生成一个文件,就像这样:

1 23
1 67
1 562
1 78
...

为了快速运行,我重写了代码。代码如下

input.txt包含16000000行。列数不固定。第1列和第2列中的唯一符号(例如,&#34; c33&#34;)的数量不固定。每两行input.txt文件都是这样的:

The 1st row  (odd row1):  c33 c21 c5 c7 c8
The 2nd row (even row1): TPS2 MIC17 ERG3 NNF1 CIS3 CWP2 MCM6
The 3rd row  (odd row2): c33 c21 c5 c21 c18 c4 c58
The 4th row (even row2): TPS12 MIC3 ERG2 NNF1 CIS4

**所需的结果: enter image description here

如果两行与其他两行重叠(> = 0.6),则输出NO。将这两行写入文件。**

代码:

 library(compiler)
    enableJIT(3)
    con <- file("input.txt", "r")
    zz<-file("output.txt","w")
    oddrow1<-readLines(con,n=1)  
    j<-0
    i<-0 
    while( length(oddrow1) != 0 ){
    oddrow1<-strsplit(oddrow1," ")
    evenrow1<-readLines(con,n=1)
    evenrow1<-strsplit(evenrow1," ")
    j<-j+1
    con2 <- file("input.txt", "r")
    readLines(con2,n=(j*2))
    oddrow2<-readLines(con2,n=1) 
    i<-j
    while( length(oddrow2) != 0 ){
       i<-i+1
       oddrow2<-strsplit(oddrow2," ")
       evenrow2<-readLines(con2,n=1)
       evenrow2<-strsplit(evenrow2," ")
       oddrow1<-unlist(oddrow1)
       oddrow2<-unlist(oddrow2)
       evenrow1<-unlist(evenrow1)
       evenrow2<-unlist(evenrow2)
       up<-length(intersect(oddrow1,oddrow2))*length(intersect(evenrow1,evenrow2))
       down<-min(length(oddrow1)*length(evenrow1),length(oddrow2)*length(evenrow2))

       if ((up/down)>=0.6) {cat(j,"\t",i,"\n",file=zz,append=TRUE)  } 
       oddrow2<-readLines(con2,n=1)
       }
    close(con2)
    oddrow1<-readLines(con,n=1)
    }
    close(con)  
    close(zz)

运行结果: 它可以生成一个文件,就像这样:

1 23
1 67
1 562
1 78
2 25
2 89
3 56
3 79
 ...

以上两种方法都太慢了,为了快速运行,如何重写这段代码。谢谢!

1 个答案:

答案 0 :(得分:1)

嗯,我怀疑为你的数据大小使用了太多的内存,但也许它会激起一些想法。

组成一些数据,每个单元格中有20个唯一值,5到10个。

set.seed(5)
n <- 1000L
ng <- 20
g1 <- paste(sample(10000:99999, ng))
g2 <- paste(sample(10000:99999, ng))
n1 <- sample(5:10, n, replace=TRUE)
n2 <- sample(5:10, n, replace=TRUE)
x1 <- sapply(n1, function(i) paste(g1[sample(ng, i)], collapse="|"))
x2 <- sapply(n2, function(i) paste(g2[sample(ng, i)], collapse="|"))

加载矩阵库和一个辅助函数,它接受一个字符串向量列表并将它们转换为一个矩阵,其列数等于唯一字符串的数量和1的位置。

library(Matrix)
str2mat <- function(s) {
  n <- length(s)
  ni <- sapply(s, length)
  s <- unlist(s)
  u <- unique(s)
  spMatrix(nrow=n, ncol=length(u), i=rep(1L:n, ni), j=match(s, u), x=rep(1, length(s)))
}

好的,现在我们可以做点什么。首先创建矩阵并获得每行中的总数。

m1 <- str2mat(strsplit(x1, "|", fixed=TRUE))
m2 <- str2mat(strsplit(x2, "|", fixed=TRUE))
n1 <- rowSums(m1)
n2 <- rowSums(m2)

现在我们可以使用这些矩阵的叉积来获得分子,而外部则可以得到最小值以获得分子。然后,我们可以计算重叠并测试是否> 0.6。由于我们有整个矩阵,我们对对角线或下半部分不感兴趣。 (有了使用Matrix库更有效地存储这种矩阵的方法,但我不确定如何。)然后我们得到与which有足够重叠的行。

num <- tcrossprod(m1)*tcrossprod(m2)
n12 <- n1*n2
den <- outer(n12, n12, pmin)
use <- num/den > 0.6
diag(use) <- FALSE
use[lower.tri(use)] <- FALSE
out <- which(use, arr.ind=TRUE)

> head(out)
     [,1] [,2]
[1,]   64   65
[2,]   27   69
[3,]   34   81
[4,]   26   82
[5,]    5   85
[6,]   21  115