Skip to content

pairs

15 messages · cindy Guo, Charlie Sharpsteen, Linlin Yan +1 more

#
cindy Guo wrote:
Use %in% to check for the presence of the numbers in a row and apply() to
efficiently execute the test for each row:

 tstMatrix <- matrix( c(2,5,1,6,
    1,7,8,2,
    3,7,6,2,
    9,8,5,7), nrow=4, byrow=T )

  matches <- apply( tstMatrix, 1, function( row ){
   
    if( 2 %in% row & 6 %in% row ){

      return( 2 )

    } else {

      return( 0 )

    }

  })

  matches
  [1] 2 0 2 0

If you have more than one pair, it gets a little tricky.  Say you are also
looking for the pair (7,8).  Store them as a list:

  pairList <- list( c(2,6), c(7,8) )

Then use sapply() to efficiently iterate over the pair list and execute the
apply() test:

  matchMatrix <- sapply( pairList, function( pair ){

    matches <- apply( tstMatrix, 1, function( row ){
    
      if( pair[1] %in% row & pair[2] %in% row ){

        return( pair[1] )

      } else {

        return( 0 )

      }

    })

    return( matches )

  })

  matchMatrix

       [,1] [,2]
  [1,]    2    0
  [2,]    0    7
  [3,]    2    0
  [4,]    0    7



If you're looking to apply the above method to every possible permutation of
2 numbers that may be generated from the range of numbers 1:15000... that's
225,000,000 pairs. expand.grid() can generate the required pair list-- but
that step alone causes a memory allocation of ~6 GB on my machine.

If you don't have a pile of CPU cores and RAM at your disposal, you can
probably:

  1. Restrict the upper end of your range to the maximal entry present in
your matrix since all other combinations have zero occurrences.

  2. Break the list of pairs up into several sublists, run the tests, and
aggregate the results.

Either way, the analysis will take some time despite the efficiencies of the
apply family of functions due to the shear size of the problem.  If you have
more than one CPU, I would recommend taking a look at parallelized apply
functions, perhaps using a package like snowfall,  as the testing of the
pairs is an "embarrassingly parallel" problem.

Hopefully I'm misunderstanding the scope of your problem.


Good luck!

-Charlie

-----
Charlie Sharpsteen
Undergraduate
Environmental Resources Engineering
Humboldt State University
#
Hope this help:
[1]  TRUE FALSE  TRUE FALSE

If you want the number of rows which contain the pair, sum() could be used:
[1] 2
On Mon, Nov 16, 2009 at 6:26 AM, cindy Guo <cindy.guo3 at gmail.com> wrote:
#
I could of course be wrong but have you yet specified the number of  
columns for this pairing exercise?
On Nov 15, 2009, at 5:26 PM, cindy Guo wrote:

            
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

David Winsemius, MD
Heritage Laboratories
West Hartford, CT
#
Assuming that the number of columns is 4, then consider this approach:

 > prs <-scan()
1: 2 5 1 6
5: 1 7 8 2
9: 3 7 6 2
13: 9 8 5 7
17:
Read 16 items
prmtx <- matrix(prs, 4,4, byrow=T)

#Now make copus of x.y and y.x

pair.str <- sapply(1:nrow(prmtx), function(z) c(apply(combn(prmtx[z,],  
2), 2,function(x) paste(x[1],x[2], sep=".")) , apply(combn(prmtx[z,],  
2), 2,function(x) paste(x[2],x[1], sep="."))) )
tpair <-table(pair.str)

# This then gives you a duplicated list
 > tpair[tpair>1]
pair.str
1.2 2.1 2.6 2.7 6.2 7.2 7.8 8.7
   2   2   2   2   2   2   2   2

# So only take the first half of the pairs:
 > head(tpair[tpair>1], sum(tpair>1)/2)

pair.str
1.2 2.1 2.6 2.7
   2   2   2   2
#
I'm not convinced it's right. In fact, I'm pretty sure the last step  
taking only the first half of the list is wrong. I also do not know if  
you have considered how you want to count situations like:

3 2 7 4 5 7 ...
7 3 8 6 1 2 9 2 ......

How many "pairs" of 2-7/7-2 would that represent?
#
I stuck in another "7" in one of the lines with a 2 and reasoned that  
we could deal with the desire for non-ordered "pair counting" by  
pasting min(x,y) to max(x,y);

 > dput(prmtx)
structure(c(2, 1, 3, 9, 5, 7, 7, 8, 1, 7, 6, 5, 6, 2, 2, 7), .Dim =  
c(4L,
4L))
 > prmtx
      [,1] [,2] [,3] [,4]
[1,]    2    5    1    6
[2,]    1    7    7    2
[3,]    3    7    6    2
[4,]    9    8    5    7

 > pair.str <- sapply(1:nrow(prmtx), function(z)   
apply(combn(prmtx[z,], 2), 2,function(x) paste(min(x[2],x[1]),  
max(x[2],x[1]), sep=".")))

The logic:
sapply(1:nrow(prmtx), ... just loops over the rows of the matrix.
combn(prmtx[z,], 2)  ... returns a two row matrix of combination in a  
single row.
apply(combn(prmtx[z,], 2), 2 ... since combn( , 2)  returns a matrix  
that has two _rows_ I needed to loop over the columns.
paste(min(x[2],x[1]), max(x[2],x[1]), sep=".") ... stick the minimum  
of a pair in front of the max and separates them with a period to  
prevent two+ digits from being non-unique

Then using table() and logical tests in an index for the desired  
multiple pairs:


 > tpair <-table(pair.str)
 > tpair
pair.str
1.2 1.5 1.6 1.7 2.3 2.5 2.6 2.7 3.6 3.7 5.6 5.7 5.8 5.9 6.7 7.7 7.8  
7.9 8.9
   2   1   1   2   1   1   2   3   1   1   1   1   1   1   1   1   1    
1   1
 > tpair[tpair>1]
pair.str
1.2 1.7 2.6 2.7
   2   2   2   3
#
David Winsemius wrote:

        
cindy Guo wrote:
No, he's suggesting you check out the order() function by calling it's help
page:

  ?order

order() will sort your results into ascending or descending order.  You
could then pick off the top 50 by using head().

Hope that helps!

-Charlie


-----
Charlie Sharpsteen
Undergraduate
Environmental Resources Engineering
Humboldt State University