我有两个矩阵 diff.exp.protein.expr 和 lncRNA.expr ,每个矩阵有64列但行数不同。
>dim(diff.exp.protein.expr)
[1] 14000 64
>dim(lncRNA.expr)
[1] 7600 64
我在两个单独的线性模型中使用这些矩阵作为输入,我将 diff.exp.protein.expr 的每一行与 lncRNA.expr 的所有行进行比较( = 2 * 1.06亿次测试)。最后,我想比较两个线性模型是否在统计上有所不同,我使用anova编写了一个函数,如下所示:
lm.anova <- function(diff.exp.protein.expr,lncRNA.expr,colData)
{
tempdff <- data.frame() #create an empty dataframe
for(i in 1:nrow(diff.exp.protein.expr)) #traverse through 1st matrix
{
for(j in 1:nrow(lncRNA.expr)) #traverse through 2nd matrix
{
#model 1
lm1 <- lm(diff.exp.protein.expr[i,]~colData$gender+colData$age+colData$treatment)
#model 2 (has an additional interaction term at the end)
lm2 <- lm(diff.exp.protein.expr[i,]~colData$gender+colData$age+colData$treatment+lncRNA.expr[j,]+colData$treatment*lncRNA.expr[j,])
#get the summary of model 2
lm.model <- summary(lm2)
#get the rownames of ith row of matrix 1 and jth row of matrix 2
#get the pvalue from the anova model
#get the estimate and std. error for last two terms of model 2
#add these values as a row to tempdff
tempdff <- rbind(tempdff,data.frame(rownames(diff.exp.protein.expr)[i],rownames(lncRNA.expr)[j],
anova(lm1,lm2)$"Pr(>F)"[2]),lm.model$coefficients[4,1:2],lm.model$coefficients[6,1:2])
}
}
return(tempdff) #return results
}
lm.anova.res <- lm.anova(diff.exp.protein.expr,lncRNA.expr,colData) #call function
这就是进入该功能的数据的样子:
>head(diff.exp.protein.expr)[,1:5] #log transformed values
C00060 C00079 C00135 C00150 C00154
ENSG00000000005.5 5.187977 6.323024 6.022986 5.376513 4.810042
ENSG00000000460.12 7.071433 7.302448 7.499133 7.441582 7.439453
ENSG00000000938.8 8.713285 8.584996 8.982816 9.787420 8.823927
ENSG00000001497.12 9.569952 9.658418 9.392670 9.394250 9.087214
ENSG00000001617.7 9.215362 9.417367 8.949943 8.172713 9.198314
ENSG00000001626.10 6.363638 6.038328 6.698733 5.202132 5.336239
>head(lncRNA.expr)[,1:5] #log transformed values
C00060 C00079 C00135 C00150 C00154
ENSG00000100181.17 7.477983 7.776463 7.950514 8.098205 7.278615
ENSG00000115934.11 4.104380 4.104380 4.104380 4.104380 4.104380
ENSG00000122043.6 4.104380 4.104380 4.104380 4.104380 4.104380
ENSG00000124915.6 4.104380 4.104380 4.104380 4.104380 4.104380
ENSG00000125514.5 4.104380 4.104380 4.104380 4.104380 4.104380
ENSG00000129816.5 4.104380 4.104380 4.104380 4.104380 4.104380
>head(colData)[,1:5] #sample information for each column of the two input matrices
sample_name status age gender site treatment
C00060 NF 48 Female Cleveland case
C00079 NF 26 Female Cleveland case
C00135 NF 55 Female Cleveland case
C00150 NF 61 Male Cleveland ctrl
C00154 NF 50 Male Cleveland case
C00176 NF 60 Female Cleveland ctrl
当我进行很少的测试(~50)时,我编写了这段代码。现在,除非我不知道如何才能使我的代码高效,因为在这种情况下使用for循环,必须执行14000 * 7600测试并没有任何意义。运行需要永远。我想知道什么是其他替代方案,我可以真正加快这段代码。任何建议都将不胜感激。
更新1 :我稍微更新了我的线性模型。现在,anova(lm1,lm2)&#34; Pr(&gt; F)&#34;不会给出与model2中的交互项相同的值。
更新2 :我更新了我的线性模型,以便lm1嵌套在lm2中。
谢谢,
答案 0 :(得分:0)
我的问题包MatrixEQTL
似乎解决了您的问题。
http://www.bios.unc.edu/research/genomic_software/Matrix_eQTL/
http://cran.r-project.org/web/packages/MatrixEQTL/index.html
您需要使用modelLINEAR_CROSS
模型来测试交互术语的重要性。
如有任何关于包裹的问题,请随时提出。
答案 1 :(得分:0)
所以有几件事情。
首先,调用data.frame(...)
非常昂贵,因此在每次迭代时调用它会大大减慢速度。另一方面,列表非常有效。因此,请尽量将所有内容保留在列表中直到结束。
其次,可能只是在大部分时间内运行2 * 1.06亿次回归。
我倾向于这样尝试:
## not tested...
df1 <- t(diff.exp.protein.expr)
df2 <- t(lncRNA.expr)
df <- cbind(df1,df2,colData)
names <- expand.grid(x=colnames(df1),y=colnames(df2),stringsAsFactors=FALSE)
get.anova <- function(n){
form.1 <- as.formula(paste0(n[1],"~gender+age+treatment+",n[2]))
form.2 <- as.formula(paste0(n[1],"~gender+age+treatment+",n[2],"+treatment:",n[2]))
lm1 <- lm(form.1,data=df)
lm2 <- lm(form.2,data=df)
coef <- summary(lm2)$coefficients
list(n[1],n[2],anova(lm1,lm2)$"Pr(>F)"[2],coef[5,1],coef[5,2],coef[6,1],coef[6,2])
}
result <- do.call(rbind,apply(names,1,get.anova))
result <- data.frame(result)
colnames(result) <- c("protein","lncRNA","p.value","est.1","se.1","est.2","se.2")
这未经过测试,因为您提供的数据集不够大:模型具有&lt; 0 df表示错误。因此,系数表中没有第6行。你真正的数据集不会有这个问题。
编辑(对OP评论和数据提供的回应)。
使用评论中提供的数据集,我们可以对原始代码(基于您更新的帖子)和新版本(基于上面的代码进行基准测试,更新以反映您的新模型公式)进行基准测试。在这两种情况下,我只使用每个数据集中的10行(100种组合)。
f.original <- function() lm.anova(diff.exp.protein.expr.sub[1:10,],lncRNA.expr.sub[1:10,],colData)
f.new <- function() do.call(rbind,apply(names,1,get.anova))
library(microbenchmark)
microbenchmark(f.original(), f.new(), times=10)
# Unit: seconds
# expr min lq median uq max neval
# f.original() 2.622461 2.712527 2.824419 2.869193 2.914099 10
# f.new() 2.049756 2.074909 2.144422 2.191546 2.224831 10
因此,我们可以看到返回列表而不是数据帧的新版本的速度提高了约25%。
使用Rprof
对这两种方法进行概要分析表明原始版本花费了lm(...)
中约50%的时间,而新版本花费了大约60%的时间。{ lm(...)
中的s(较短)时间。这是有道理的,并表明你可能做的最好的是比新版本提高约30%。换句话说:对lm(...)
的调用是瓶颈:对lm(...)
的2亿次调用只需要很长时间。
您可以考虑使用并行计算方法,例如使用foreach
package,但在走向IMO之前,您应该考虑采用其他策略来获得最终结果。
答案 2 :(得分:0)
此处的主要时间消费者不是嵌套循环,而是lm
。以下是您可以优化的一些事项(但另请参阅Andrey Shabalin的回答 - 他可能会为您的案例提供更简单的解决方案)。
你有两个lm,简化形式:
lm1 <- lm(Y~ X1 + X2 + X3 + X4)
lm2 <- lm(Y~ X1 + X2 + X3 + X4 + X3:X4)
然后您制作summary
lm2
并将lm1
与anova
进行比较。因为您只从anova
中提取p值,但p值与lm2中交互项的p值相同,所以执行anova
是多余的。因此lm1
也是多余的。然后使用rbind
来增加数据框是浪费时间,所以我建议使用列表并在每次迭代时添加一个新元素。所以循环中的代码可以简化为:
# lm1 <- ... # skip this
#model 2 (has an additional interaction term at the end)
lm2 <- lm(diff.exp.protein.expr[i,]~colData$gender+colData$age+colData$treatment+lncRNA.expr[j,]+lncRNA.expr[j,]:colData$treatment)
#get the summary of model 2, * and coefficients from that summary *
lms <- coef(summary(lm2))
tempdff[[length(tempdff)+1]] <- data.frame(rownames(diff.exp.protein.expr)[i],
rownames(lncRNA.expr)[j], lms[6,4],lms[5,1:2],lms[6,1:2])
此外,您将结果作为data.frame - 使用list
代替也可以节省一些时间。
下一步可能是检查lm
和summary.lm
正在做什么。你不需要它所做的一切,你只需要使用b及其标准错误,以及最后一行的p值。您可以在某些矩阵代数的帮助下跳过lm
和summary.lm
所做的一些计算。