【发布时间】:2018-02-15 08:09:39
【问题描述】:
我使用基因组数据,我经常需要运行一百万个或更多的回归模型。我在下面的循环可以工作,但是速度很慢,并且由于附加每条新记录的开销而持续时间越长越慢。
#### setup sample data ###
require(data.table)
data <- data.frame(
C = rnorm(10, 5),
D = rnorm(10, 7),
E = rnorm(10, 9),
A = rnorm(10, 1),
B = rnorm(10, 3)
)
outcome <- c(rnorm(10, 5))
cov <- data.frame(cov1 = c(1, 1, 1, 2, 2, 1, 1, 1, 2, 2))
#### initialize results file ###
myresults <- data.table(NULL)
#### Run regression against same covariates and outcome for each column in data ##
for (i in 1:ncol(data)) {
id = colnames(data)[i]
mydata <- cbind(cov, outcome, data[, id])
colnames(mydata)[ncol(mydata)] <- id #I can't figure out how to not have to do this
fit <-
glm(formula(paste0("outcome ~ as.factor(cov1) + ", id)), data = mydata)
myresults <- rbindlist(list(
myresults,
data.table(
id = id,
estimate = signif(coef(summary(fit))[id, "Estimate"], digits = 4),
pvalue = signif(coef(summary(fit))[id, "Pr(>|t|)"], digits = 4)
)
))
}
myresults
这给出了我所需要的输出结果文件。我可以修改它以添加其他输出,在循环中运行其他模型以按协变量进行分层,然后捕获等...我的输出始终具有与初始 data 中的列相同数量的数据行数。
id estimate pvalue
1: C -0.22220 0.49230
2: D 0.64550 0.08568
3: E -0.06756 0.83990
4: A 0.39750 0.54060
5: B -0.34300 0.35410
通过切换到您在循环中看到的data.table::rbindlist,我能够获得一些改进。
我一直在尝试使用lapply(split(data, colnames(data))) 之类的东西来看看我是否可以加快速度,甚至可能使用mclapply(),但一直无法让它工作。
非常感谢您的帮助。
编辑:我支持所有回复的人,因为他们都很有帮助,我很感激所花费的时间。
以 6 倍的优势明显获胜的是 Roland 的评论。我列出了我在这里为后代所做的事情,以防它可以帮助其他人。
我合并到一个非常宽的数据集 (260 x 470,000)
require(data.table)
require(reshape2)
bigdata <- cbind(mycovs, testdata)
test <- data.table(bigdata)
然后我把它做成了一个高大的数据集:
DT.m1 = melt(
test,
id.vars = c(
"Sample_Plate",
"BaseName",
"Race",
"Education",
"mom_age_delv",
"sex",
"gest_age_wks",
"MONTH_OLD",
"DEPRESSION",
"CD8T",
"CD4T",
"NK",
"Bcell",
"Mono",
"Gran"
),
measure.vars = c(16:ncol(test)),
variable.name = "cpg",
value.name = "betaval"
)
然后我运行我的完整回归模型并从系数表中取出最后一行,如下所示:
system.time(res <-
DT.m1[, {
fit <-
glm(
DEPRESSION ~ as.factor(Sample_Plate) + as.factor(sex) + as.factor(Education) + as.factor(Race) + MONTH_OLD + mom_age_delv + gest_age_wks + CD8T + CD4T + NK + Bcell + Mono + Gran + betaval,
data = .SD
)
coef(summary(fit))[nrow(coef(summary(fit))), c(1, 2, 4)]
}, by = cpg])
最后,我清理了它。
res <- cbind(res, c("beta1", "se", "pvalue"))
head(res)
final_results <- dcast(data = res, cpg ~ V2, value.var = "V1")[c(1, 2, 4, 3)]
这导致每 1000 个模型的时间约为 10 秒。下一个关闭时间是~60 秒。
清理部分似乎应该可以在 data.table() 中完成,但我无法弄清楚。我只能为我请求的每个 coef 列重复一个高 2 列向量。
如果您对如何改进有其他想法,请告诉我,再次感谢。
【问题讨论】:
-
您可能会研究并行性、多核和 GPU 策略等。不过,这对于 Stack Overflow 来说有点宽泛。您可能想尝试 Code Review SE。 codereview.stackexchange.com
-
这看起来很可疑。您可能可以做一些比产生这些无用 p 值更明智的事情。无论如何,第一步:使您的数据成为 data.table 并重塑为长格式,第二步:DT[, {fit ; },按 = 变量]。根据需要进行调整。
-
感谢您的意见@Roland。关于有效性,阅读 GWAS SNP 测试或 CpG 甲基化标记测试,并使用调整后的 pvalues 和 qqplots 来确定显着性;如果您愿意,我们可以在某个时候进行边栏聊天。
标签: r loops split regression apply