Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

counting N occurrences within a ceiling range of a matrix by-row

I would like to tally each time a value lies within a given range in a matrix by-row, and then sum these logical outcomes to derive a "measure of consistency" for each row.

Reproducible example:

m1 <- matrix(c(1,2,1,6,3,7,4,2,6,8,11,15), ncol=4, byrow = TRUE)


# expected outcome, given a range of +/-1 either side

exp.outcome<-matrix(c(TRUE,TRUE,TRUE,FALSE,
                          TRUE,FALSE,TRUE,TRUE,
                          FALSE,FALSE,FALSE,FALSE), 
                          ncol=4, byrow=TRUE)

Above I've indicated the the expected outcome, in the case where each value lies within +/- 1 range of any other values within that row.

Within the first row of m1 the first value (1) is within +/-1 of any other value in that row hence equals TRUE, and so on.

By contrast, none of the values in row 4 of m1 are within a single digit value of each other and hence each is assigned FALSE.

Any pointers would be much appreciated?

Update:

Thanks to the help provided I can now count the unique pairs of values which meet the ceiling criteria for any arbitrarily large matrix (using the binomial coefficient, k draws from n, without replacement).

Ball Picking: Drawing unsorted, without replacement.

like image 619
danny_C_O_T_W Avatar asked Jun 16 '16 14:06

danny_C_O_T_W


2 Answers

Before progressing with the answer I just wanted to clarify that in your question you have said:

Within the first row of m1 the first value (1) is within +/-1 of any other value in that row hence equals TRUE, and so on.

However,

>> m1[1,4]
[1] 6

6 is not within the +/- 1 from 1, and there is FALSE value as a correct result in your answer.

Solution

This solution should get you to the desired results:

t(apply(
    X = m1,
    # Take each row from the matrix
    MARGIN = 1,
    FUN = function(x) {
        sapply(
            X = x,
            # Now go through each element of that row
            FUN = function(y) {
                # Your conditions
                y %in% c(x - 1) | y %in% c(x + 1)
            }
        )
    }
))

Results

      [,1]  [,2]  [,3]  [,4]
[1,]  TRUE  TRUE  TRUE FALSE
[2,]  TRUE FALSE  TRUE  TRUE
[3,] FALSE FALSE FALSE FALSE

Check

For results stored as res.

>> identical(res, exp.outcome)
[1] TRUE
like image 143
Konrad Avatar answered Sep 21 '22 14:09

Konrad


Here is a kind of neat base R method that uses an array:

The first two lines are setup that store a three dimensional array of acceptable values and a matrix that will store the desired output. The structure of the array is as follows: columns correspond with acceptable values of a matrix element in same column. The third dimension correspond with the rows of the matrix.

Pre-allocation in this way should cut down on repeated computations.

# construct array of all +1/-1 values
valueArray <- sapply(1:nrow(m1), function(i) rbind(m1[i,]-1, m1[i,], m1[i,]+1),
                     simplify="array")

# get logical matrix of correct dimensions
exp.outcome <- matrix(TRUE, nrow(m1), ncol(m1))

# get desired values
for(i in 1:nrow(m1)) {
  exp.outcome[i, ] <- sapply(1:ncol(m1), function(j) m1[i, j] %in% c(valueArray[, -j, i]))
}

Which returns

exp.outcome
      [,1]  [,2]  [,3]  [,4]
[1,]  TRUE  TRUE  TRUE FALSE
[2,]  TRUE FALSE  TRUE  TRUE
[3,] FALSE FALSE FALSE FALSE
like image 41
lmo Avatar answered Sep 24 '22 14:09

lmo