我有两个数据框/数据列表'humanSplit and
ratSplit`,它们的格式为
> ratSplit$Kidney_F_GSM1328570
ratGene ratReplicate alignment RNAtype
1 Crot Kidney_F_GSM1328570 7 REV
2 Crot Kidney_F_GSM1328570 12 REV
3 Crot Kidney_F_GSM1328570 4 REV
和
> humanSplit$Fetal_Brain_408_AGTCAA_L009_R1_report.txt
humanGene humanReplicate alignment RNAtype
53 ZFP28 Fetal_Brain_408_AGTCAA_L009_R1_report.txt 5 reg
55 RC3H1 Fetal_Brain_408_AGTCAA_L009_R1_report.txt 9 reg
56 IFI27 Fetal_Brain_408_AGTCAA_L009_R1_report.txt 4 reg
下面使用的另一个文件是formList:
ABAT,Abat
ABCA1,Abca1
ABCA12,Abca12
ABCA2,Abca2
ABCA3,Abca17
ABCA4,Abca4
ABCA5,Abca5
现在我想在一些数据操作之后对ratSplit
和humanSplit
之间的所有元素对组合进行Fisher精确测试。最终想在csv
文件中写出fisher测试的结果。现在我正在做双循环。但我想知道如何使用sapply
或其他相关的东西来提高效率。
目前我正在做以下事情:这里我首先制作一个data.frame
result
,我在每一步中存储/追加从Fisher测试中得到的所有信息。最后,当整个循环完成后,我在result
文件中写下最终的csv
。我的理解是使用sapply
我需要将循环内部转换为函数然后调用sapply。但我不确定优化它的最佳方法是什么。任何帮助将不胜感激
result <- data.frame(humanReplicate = "human_replicate", ratReplicate = "rat_replicate", pvalue = "p-value", alternative = "alternative_hypothesis",
Conf.int1 = "conf.int1", Conf.int2 ="conf.int2", oddratio = "Odd_Ratio")
for(i in 1:length(ratSplit)) {
for(j in 1:length(humanSplit)) {
ratReplicateName <- names(ratSplit[i])
humanReplicateName <- names(humanSplit[j])
#merging above two based on the one-to-one gene mapping as in geneList defined above.
mergedHumanData <-merge(geneList,humanSplit[[j]], by.x = "human", by.y = "humanGene")
mergedRatData <- merge(geneList, ratSplit[[i]], by.x = "rat", by.y = "ratGene")
mergedHumanData <- mergedHumanData[,c(1,2,4,5)] #rearrange column
mergedRatData <- mergedRatData[,c(2,1,4,5)] #rearrange column
mergedHumanRatData <- rbind(mergedHumanData,mergedRatData) #now the columns are "human", "rat", "alignment", "RNAtype"
agg <- aggregate(RNAtype ~ human+rat, data= mergedHumanRatData, FUN=getGeneType) #agg to make HmYn form
HmRnTable <- table(agg$RNAtype) #table of HmRn ie RNAtype in human and rat.
#now assign these numbers to variables HmYn. Consider cases when some form of HmRy is not present in the table. That's why
#is.integer0 function is used
HyRy <- ifelse(is.integer0(HmRnTable[names(HmRnTable) == "HyRy"]), 0, HmRnTable[names(HmRnTable) == "HyRy"][[1]])
HnRn <- ifelse(is.integer0(HmRnTable[names(HmRnTable) == "HnRn"]), 0, HmRnTable[names(HmRnTable) == "HnRn"][[1]])
HyRn <- ifelse(is.integer0(HmRnTable[names(HmRnTable) == "HyRn"]), 0, HmRnTable[names(HmRnTable) == "HyRn"][[1]])
HnRy <- ifelse(is.integer0(HmRnTable[names(HmRnTable) == "HnRy"]), 0, HmRnTable[names(HmRnTable) == "HnRy"][[1]])
contingencyTable <- matrix(c(HnRn,HnRy,HyRn,HyRy), nrow = 2)
fisherTest <- fisher.test(contingencyTable)
newLine <- data.frame(t(c(humanReplicate = humanReplicateName, ratReplicate = ratReplicateName, pvalue = fisherTest$p,
alternative = fisherTest$alternative, Conf.int1 = fisherTest$conf.int[1], Conf.int2 =fisherTest$conf.int[2],
oddratio = fisherTest$estimate[[1]])))
result <-rbind(result,newLine)
}
}
write.table(result, file = "newData5.csv", row.names = FALSE, append = FALSE, col.names = TRUE, sep = ",")
答案 0 :(得分:1)
我们很难对此进行测试,因为我们错过了geneList
,但我推断代码工作正常,所以您只想加快速度。以下是一些帮助提示:
不要像这样定义result
。通过将每列的第一个条目设置为列名的字符串,可以确保将所有后续条目强制转换为字符串。虽然这并不一定会让你感到厌烦,因为无论如何你最终还是写了一个CSV,这是一个糟糕的形式。如果你打算将它读回R,它会咬你,因为第一行将用作列名,但第二行都是字符串,强制后续数据也是字符串。 (然后你必须清理你自己的数据,浪费。)
在脚本结束时,您致电rbind
。这可能会好一段时间,但重复调用rbind
将导致每次都复制整个data.frame。随着附加更多行,这将导致代码中的无意义的减速。这可以通过下面列出的两种方法之一来解决。
由于你每次使用names(HmRnTable) == "HyRy"
两次,我的技术是首先将它保存到一个向量(如果使用which(...)
,则为标量),然后在子集的子集中使用此变量HmRnTable
。它可能会加快一点,但也可能使代码更容易阅读。实际上,您可以将这四个任务中的每一个缩短为(未经测试):
idx <- is.integer0(HmRnTable[names(HmRnTable) == 'HyRy'])
HyRy <- HmRnTable[idx][[1]]
HyRy[idx] <- 0
## repeat for HyRn, HnRy, and HnRn
我强烈建议你把大部分代码放在一个带有两个参数(i
和j
)或四个参数(list1,index1,list2)的函数中,index2)。 (你所做的取决于你对变量范围引用有多少强迫症。)我假设该函数将从fisher.test
字面上返回结果而不进行按摩。这将使得在创建函数时更容易进行测试,并且稍后将在此脚本中包含。我将下面的myfisher(i,j)
引用功能。
我推断你要进行大量的比较(因为每次迭代都不应该花那么长时间)。 @ Floo0关于outer
的评论可以正常工作,expand.grid
也可以。无论哪种方式,您都将list1的每个元素与list2的每个元素进行比较。如果您从:
(eg <- expand.grid(i = 1:length(ratSplit),
j = 1:length(humanSplit)))
## i j
## 1 1 1
## 2 2 1
## 3 3 1
## 4 4 1
## ...
这为我们提供了一个简单的data.frame,我们可以使用 请注意,我明确没有包含 这些名字也会神奇地出现在输出中。较少处理循环内部。 到目前为止,这将产生一个data.frame,然后您可以将其保存为CSV。 我将再提出一项可能过度的建议,具体取决于此项运行的时间长短。我有时发现我长时间运行的脚本被打断了,也许是因为我必须在运行中调整一些东西;我发现了一个bug;或者如果计算机必须重新启动没有简单的方法允许中流继续,但我已经采用了一些技术来缓解这种情况。apply
。但老实说,在这种情况下,我喜欢ddply
的优雅,因为它可以轻松地从一个data.frame 到一个data.frame。 / p>
library(plyr)
ret <- ddply(eg, .(i, j), function(df) {
with(myfisher(df$i, df$j),
data.frame(pv = p.value, ci1 = conf.int[1], ci2 = conf.int[2],
alt = alternative))
})
humanReplicateName
或ratReplicateName
,因为这些可以在ddply之前(或之后,引用ret$
而不是eg$
)添加:< / p>
eg$ratReplicateName <- names(ratSplit[ eg$i ])
eg$humanReplicateName <- names(humanSplit[ eg$i ])
使用不假定返回值类型的ddply
而不是d_ply
。而不是返回(单行)data.frame,立即将该行(带或不带标题,您的调用)保存到文件中。虽然下面的代码不是真正的&#34; atomic&#34;因此可能会出现 的竞争条件,它足以满足我们的大部分需求:
library(plyr)
savedir <- './output'
ret <- ddply(eg, .(i, j), function(df) {
fn <- file.path(savedir, sprintf('%s-%s.csv', df$i, df$j))
if (! file.exists(fn)) {
ret <- with(myfisher(df$i, df$j),
data.frame(pv = p.value, ci1 = conf.int[1], ci2 = conf.int[2],
alt = alternative))
write.table(ret, file = fn, sep = ",", append = FALSE,
row.names = FALSE, col.names = TRUE)
}
})
这样做的一个优点是,如果/当它被中断时,您需要做的 most 就是查看&#34; ./ output /&#34;中的所有文件。 ,删除0字节的文件,然后重新运行,它只会在丢失的文件上执行。哦,它变得更好。
并行化。如果你需要走得这么远(有些功能看不到其他功能),你可以在系统上使用多个内核。你可以这样做:
library(parallel)
cl <- makeCluster(detectCores() - 1) # I like to keep one free
clusterEvalQ(cl, {
load('myTwoLists.rda') # with ratSplit and humanSplit variables
source('mycode.R') # with myfisher(i,j)
## any libraries you may want/need to add, if you get more advanced
})
eg <- expand.grid(i = 1:length(ratSplit),
j = 1:length(humanSplit))
eg$ratReplicateName <- names(ratSplit[ eg$i ])
eg$humanReplicateName <- names(humanSplit[ eg$i ])
ign <- parApply(cl, eg, 1, function(r) {
i <- r[1] ; j <- r[2]
fn <- file.path(savedir, sprintf('%s-%s.csv', i, j)
if (! file.exists(fn)) {
ret <- with(myfisher(i, j),
data.frame(ratName = r[3], humanName = r[4],
pv = p.value, ci1 = conf.int[1], ci2 = conf.int[2],
alt = alternative))
write.table(ret, file = fn, sep = ",", append = FALSE,
row.names = FALSE, col.names = TRUE)
}
})
stopCluster(cl)
请注意,我们不再将该行作为data.frame引用。如果哈德利的代码本地并行工作,我会喜欢它。 (据我所知,确实如此,我还没找到它!) 编辑:我以前使用parallel
的项目都没有使用ddply
,反之亦然,所以我从未玩过使用ddply(..., .parallel = TRUE)
的{{1}}。
警告Emptor :此代码尚未在此上下文中进行测试,但它几乎是从工作代码中复制/粘贴的。由于编辑,我可能是一个接一个或错过了一个paren。希望它有所帮助!