将两列与另外两列进行匹配

11
我有多行数据(用制表符分隔)。我想找到在每一行中与两个列(第三和第四列)匹配的元素,这些元素分别对应于另外两个列(第十和第十一列)。例如,在第一行中,在第三和第四列中的 95428891 和 95443771 分别与第19行中的第十和第十一列匹配。同样地,也可以找到第19行中的第三和第四列分别与第一行中的第十和第十一列匹配。我需要遍历每一行并输出相应匹配的行索引。有时只有一个列匹配而不是两个(因为有时会有重复的数字),但我只需要选择两个列都匹配且存在互相匹配的行。因此,最好输出具有互相匹配的行索引,例如,“1和19”作为制表符分隔的值(可能在不同的数据框对象中)。那些没有互相匹配的行可以单独输出。我正在尝试在 R 中实现此操作以遍历多行数据。
1313    chr2    95428891    95443771    14880   chr2:96036782   205673  +   chr2    96036782    96052481
1313    chr2    95428896    95443771    14875   chr2:97111880   205214  -   chr2    97111880    97127588
1313    chr2    95443771    95526464    82693   chr2:95609272   1748861 -   chr2    95609272    95691902
1313    chr2    95477143    95486318    9175    chr2:97616847   177391  +   chr2    97616847    97626039
1313    chr2    95486323    95521267    34944   chr2:97035158   268351  +   chr2    97035158    97070183
1313    chr2    95515418    95525958    10540   chr2:95563236   132439  +   chr2    95563236    95572666
1314    chr2    95563236    95572666    9430    chr2:95515418   132439  +   chr2    95515418    95525958
1314    chr2    95563236    95572666    9430    chr2:95609778   126017  -   chr2    95609778    95620287
1314    chr2    95563236    95569115    5879    chr2:97064308   89848   +   chr2    97064308    97070183
164     chr2    95609272    95691902    82630   chr2:95443771   1748861 -   chr2    95443771    95526464
1314    chr2    95609778    95620287    10509   chr2:95563236   126017  -   chr2    95563236    95572666
1314    chr2    95614473    95649363    34890   chr2:97035158   394821  -   chr2    97035158    97070173
1314    chr2    95649368    95658543    9175    chr2:97616847   177822  -   chr2    97616847    97626039
164     chr2    95775062    95814080    39018   chr2:97578938   0       -   chr2    97578938    97616780
1315    chr2    95778788    95781856    3068    chr2:97609982   31302   -   chr2    97609982    97616788
164     chr2    95780657    95829665    49008   chr2:96053880   882178  -   chr2    96053880    96102738
1316    chr2    95829982    95865446    35464   chr2:97296848   242680  -   chr2    97296848    97333087
1316    chr2    95829982    95935104    105122  chr2:97438085   1169669 +   chr2    97438085    97544431
1317    chr2    96036782    96052481    15699   chr2:95428891   205673  +   chr2    95428891    95443771
3个回答

24

接受的答案是可行的,但是对于相当大的数组,通常超过50k左右,您将遇到内存问题,因为您创建的矩阵非常巨大。

我会做类似这样的事情:

match(
  interaction( indat$V3, indat$V10),
  interaction( indat$V4, indat$V11)
);

将所有感兴趣的值连接为因子,然后进行匹配。

不确定这是否更快,但它更节省内存。


11

您并未指明什么是正确答案,并且当您谈到“存在互为倒数的匹配项”时,术语有些模糊。但是,如果我正确理解任务是查找所有列中col.3 == col.10 & col.4 == col.11的行,则以下代码可以完成此任务:

which( outer(indat$V4, indat$V11, "==") & 
       outer(indat$V3, indat$V10, "=="), 
       arr.ind=TRUE)
# result
      row col
 [1,]  19   1
 [2,]  10   3
 [3,]   7   6
 [4,]   8   6
 [5,]   6   7
 [6,]  11   8
 [7,]   3  10
 [8,]   7  11
 [9,]   8  11
[10,]   1  19

外部函数将一个函数'FUN'(在本例中为"==")应用于x和y的所有双向组合,从而得到一个n x n的逻辑值矩阵。我正在取这两个矩阵的逻辑“与”(and)。因此,在匹配其他行的情况下,这些行即为:

unique( c(which( outer(indat$V4, indat$V11, "==") & 
outer(indat$V3, indat$V10, "=="), 
arr.ind=TRUE) ))

#[1] 19 10  7  8  6 11  3  1

假设有一个名为indat的数据框,那么没有匹配项的集合是:

matches <- unique( c(which( outer(indat$V4, indat$V11, "==") & 
                      outer(indat$V3, indat$V10, "=="), arr.ind=TRUE) ))
indat[ ! 1:NROW(indat) %in% matches, ]

有匹配项的是:

indat[ 1:NROW(indat) %in% matches, ]

谢谢您的回答。我所说的互补匹配是指......看一下第1行和第19行。第1行中第3、4列的值与第19行中第10、11列的值相同。同样,第19行中第3、4列的值与第1行中第10、11列的值相同。因此输出第1行和第19行。类似地,第6行和第7行在第3、4列和第10、11列中也有互补匹配。 - user645600
@user645600 我的解决方案肯定已经识别了那些情况。我的勾选标记在哪里? - IRTFM
@ 什么是勾选标记?我很少使用这个论坛,不确定协议是什么。 - user645600
你能否也解释一下 arr.ind=TRUE 的作用是什么?谢谢。 - ambrish dhaka

1
下面的函数 compare 利用 R 的快速排序能力。函数参数 ab 是矩阵;在 a 中的行会被筛选,以匹配在 b 中任意数量列中的行。如果列顺序不重要,则设置 row_order=TRUE 以使行条目按升序排序。猜测该函数也适用于数据框和字符/因子列,以及在 a 和/或 b 中存在重复条目。尽管使用了 for & while,但相对快速地返回了每个 a 行的第一个匹配行(或 0,如果未找到匹配项)。
compare<-function(a,b,row_order=TRUE){

    len1<-dim(a)[1]
    len2<-dim(b)[1]
    if(row_order){
        a<-t(apply(t(a), 2, sort))
        b<-t(apply(t(b), 2, sort))
    }
    ord1<-do.call(order, as.data.frame(a))
    ord2<-do.call(order, as.data.frame(b))
    a<-a[ord1,]
    b<-b[ord2,] 
    found<-rep(0,len1)  
    dims<-dim(a)[2]
    do_dims<-c(1:dim(a)[2])
    at<-1
    for(i in 1:len1){
        for(m in do_dims){
            while(b[at,m]<a[i,m]){
                at<-(at+1)      
                if(at>len2){break}              
            }
            if(at>len2){break}
            if(b[at,m]>a[i,m]){break}
            if(m==dims){found[i]<-at}
        }
        if(at>len2){break}
    }
    return(found[order(ord1)]) # indicates the first match of a found in b and zero otherwise

}


# example data sets:
a <- matrix(sample.int(1E4,size = 1E4, replace = T), ncol = 4)
b <- matrix(sample.int(1E4,size = 1E4, replace = T), ncol = 4)
b <- rbind(a,b) # example of b containing a


# run the function
found<-compare(a,b,row_order=TRUE)
# check
all(found>0) 
# rows in a not contained in b (none in this example):
a[found==0,]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接