match two columns with two other columns
I have several rows of data (tab separated). I want to find the row which matches elements from two columns (3rd & 4th) in each row with two other columns (10th & 11th) . For example, in row 1 , 95428891 & 95443771 in column 3 & 4 matches elements in columns 10 & 11 in row 19 . Similarly the reciprocal is also true. Elements in columns 3 & 4 in the 19th row also match elements in columns 10 & 11 in row 1 . I need to be able to go through each row and output row indices for corresponding matches. It is possible that sometimes only one of the columns match instead of both (because sometimes there are duplicate numbers), but I need to pick only rows where both columns match and also where there is reciprocal match. So it would be a good idea to output row indices where there is reciprocal match, for eg., 1 & 19 as tab separated values (maybe in a different data.frame object). And the rows that do not have reciprocal matches can be output separately. I am trying to implement this in R to run through several rows of data.
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
You have not indicated what you would consider a correct answer and your terminology seems a bit vague when you talk about "where there is a reciprocal match", but if I understand the task correctly as finding all rows where col.3 == col.10 & col.4 == col.11, then this should accomplish the task:
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
The outer function applies a function 'FUN', in this case "==", to all two-way combinations of x and y, its first and second arguments, so here we get an nxn matrix with logical entries and I am taking the logical 'and' of two such matrices. So the rows where there are matches with other rows are:
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
So the set with no matches, assuming a data.frame named indat, is:
matches <- unique( c(which( outer(indat$V4, indat$V11, "==") &
outer(indat$V3, indat$V10, "=="), arr.ind=TRUE) ))
indat[ ! 1:NROW(indat) %in% matches, ]
And the ones with matches are:
indat[ 1:NROW(indat) %in% matches, ]
DWin's answer is solid, however with large-ish arrays, typically over 50k or so you'll run into memory issues, as the matrices you're creating are huge.
I'd do something like:
match(
interaction( indat$V3, indat$V10),
interaction( indat$V4, indat$V11)
);
Which concatenates all the values of interest into factors and does a match.
This is a less pure solution, but faster/more manageable.
The below function compare
takes advantage of R´s capability for fast sorting. Function arguments a
and b
are matrices; rows in a
are screend for matching rows in b
for any number of columns. In case column order is irrelevant, set row_order=TRUE
to have the row entries sorted in increasing order. Guess the function should work as well with dataframes and character / factors columns, as well as duplicate entries in a
and/or b
. Despite using the for
& while
it´s relatively quick in returning the first row match in b
for each row of a
(or 0
, if no match is found).
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,]
链接地址: http://www.djcxy.com/p/24910.html
上一篇: 组合R中具有不同行数的两个数据帧
下一篇: 将两列与另外两列进行匹配