>我在这里发布了一个问题:R中的匹配范围合并,关于根据一个文件中的数字合并两个文件,落入第二个文件中的范围。到目前为止,我一直没有成功地拼凑代码来完成这项工作。我遇到的问题是我使用的代码逐行比较文件。这是一个问题,因为 1.)一个文件比另一个文件长得多,而 2.)我需要通过较长文件中的每个范围对扫描较短文件中的行 - 而不仅仅是同一行中的范围。
我一直在使用原始问题中发布的函数,我觉得应该有一种方法可以将其应用于更通用的循环,该循环将第一个文件中的每一行与第二个文件中的每一行进行比较,但我还没有弄清楚。如果有人有任何建议,我将不胜感激。
****编辑。
数据的性质是这样的:每个范围不一定是唯一的,尽管大多数都是唯一的。它们的大小也不相等,有些完全属于其他大小。 因此,findInterval
会产生错误,因为无法对范围进行排序以按"非递减"顺序排列。
以下是每个数据框的前 6 行:
file1test <- data.frame(SNP=c("rs2343", "rs211", "rs754", "rs854", "rs343", "rs626"), BP=c(860269, 369640, 861822, 367934, 706940, 717244))
file2 <- data.frame(Gene=c("E613", "E92", "E49", "E3543", "E11", "E233"), BP_start=c(367640, 621059, 721320, 860260, 861322, 879584), BP_end = c(368634, 622053, 722513, 879955, 879533, 894689))
因此,如您所见,第 5 行的范围位于第 4 行的范围内,第一个文件中的两个 SNP 落在第 4 行的范围内,但只有一个落在第二行的范围内。
第一个包含 SNP 的文件只有 ~400 行。但是,包含范围的第二个文件大约有 20K。我想作为输出生成的是一个数据框,其中包含第一个文件(SNP)中的行,其中BP落入第二个文件中的BP范围。如果SNP分为两个范围,那么它将出现两次,依此类推。
Bioconductor中的GenomicRanges软件包专为此类操作而设计。读取您的数据,例如,read.delim,以便
con <- textConnection("SNP BP
rs064 12292
rs319 345367
rs285 700042")
snps <- read.delim(con, head=TRUE, sep="")
con <- textConnection("Gene BP_start BP_end
E613 345344 363401
E92 694501 705408
E49 362370 368340") ## missing trailing digit on BP_end??
genes <- read.delim(con, head=TRUE, sep="")
然后从每个中创建"IRanges"
library(IRanges)
isnps <- with(snps, IRanges(BP, width=1, names=SNP))
igenes <- with(genes, IRanges(BP_start, BP_end, names=Gene))
(请注意坐标系,IRanges 期望开始和结束包含在范围内;此外,当结束 = 开始 - 1 时,结束>= 开始期望 0 宽度范围)。然后找到与基因重叠的SNP(IRanges术语中的"查询")("受试者")
olaps <- findOverlaps(isnps, igenes)
其中两个SNP重叠
> queryHits(olaps)
[1] 2 3
它们重叠了第一和第二基因
> subjectHits(olaps)
[1] 1 2
如果一个查询与多个基因重叠,它将在queryHits中重复(反之亦然)。然后,您可以将数据框合并为
> cbind(snps[queryHits(olaps),], genes[subjectHits(olaps),])
SNP BP Gene BP_start BP_end
2 rs319 345367 E613 345344 363401
3 rs285 700042 E92 694501 705408
通常基因和SNP具有染色体和链("+","-"或"*"以表示链不重要)信息,并且您希望在这些上下文中进行重叠;而不是创建"IRanges"实例,而是创建"GRanges"(基因组范围),随后的簿记将为您处理
library(GenomicRanges)
isnps <-
with(snps, GRanges("chrA", IRanges(BP, width=1, names=SNP), "*")
igenes <-
with(genes, GRanges("chrA", IRanges(BP_start, BP_end, names=Gene), "+"))
你要求的是一个conditional join
.它们在 SQL 中很容易,并且 sqldf
包使使用 SQL 在 R 中查询数据帧变得容易。
只需选择一个版本,具体取决于您希望如何处理不匹配的 SNP。
内部联接版本:
> sqldf("select * from file1test f1 inner join file2 f2
+ on (f1.BP > f2.BP_start and f1.BP<= f2.BP_end) ")
输出:
SNP BP Gene BP_start BP_end
1 rs2343 860269 E3543 860260 879955
2 rs754 861822 E3543 860260 879955
3 rs754 861822 E11 861322 879533
4 rs854 367934 E613 367640 368634
>
左联版本:
> sqldf("select * from file1test f1 left join file2 f2
+ on (f1.BP > f2.BP_start and f1.BP<= f2.BP_end) ")
输出:
SNP BP Gene BP_start BP_end
1 rs2343 860269 E3543 860260 879955
2 rs211 369640 <NA> NA NA
3 rs754 861822 E3543 860260 879955
4 rs754 861822 E11 861322 879533
5 rs854 367934 E613 367640 368634
6 rs343 706940 <NA> NA NA
7 rs626 717244 <NA> NA NA
>
请注意,如果BP与BP_start或BP_end完全匹配的情况,如果BP将属于哪个组很重要,则可能需要小心放置=
的位置。
apply
和 which
按范围合并。要仅返回匹配的那些(内部连接):
do.call(rbind, apply(file1test, 1, function(x) {
if(length(idx <- which(x["BP"] >= file2$BP_start & x["BP"] <= file2$BP_end)) > 0) {
cbind(rbind(x), file2[idx,])
}
}))
# SNP BP Gene BP_start BP_end
#x rs2343 860269 E3543 860260 879955
#1 rs754 861822 E3543 860260 879955
#2 rs754 861822 E11 861322 879533
#x1 rs854 367934 E613 367640 368634
或全部来自 File1Test(左连接):
do.call(rbind, apply(file1test, 1, function(x) {
if(length(idx <- which(x["BP"] >= file2$BP_start & x["BP"] <= file2$BP_end)) > 0) {
cbind(rbind(x), file2[idx,])
} else {
cbind(rbind(x), file2[1,][NA,])
}
}))
# SNP BP Gene BP_start BP_end
#x rs2343 860269 E3543 860260 879955
#x1 rs211 369640 <NA> NA NA
#1 rs754 861822 E3543 860260 879955
#2 rs754 861822 E11 861322 879533
#x2 rs854 367934 E613 367640 368634
#x3 rs343 706940 <NA> NA NA
#x4 rs626 717244 <NA> NA NA