Comparing numbers in each row of a square matrix

I need to write a generalizable code to compare numbers in each row of a square matrix. Let's assume a 3x3 matrix

a11 a12 a13
a21 a22 a23
a31 a32 a33

I want to write a code to check if the succeeding number in each row is greater than or equal to the preceding number.

So for row 1, there are three comparisons: a12 >= a11, a13 >= a12 and a13>=a11
For row 2 also there are three comparisons: a22 >= a21, a23 >= a22 and a23>=a21
and three comparisons to be made for row 3: a32 >= a31, a33 >= a32 and a33>=a31

So a total of 9 comparisons for a 3x3 matrix. I need to store the comparison result as a vector that will have 9 values for each comparison: taking the value 1 if the succeeding number in each row is greater than or equal to the preceding number and taking the value 0 if the succeeding number in each row is less than the preceding number. I know that I first need to start with creating a vector (let's say z) that has 9 elements (each set to 0 initially):

z<-rep(0,9)

This would be followed by a loop on the rows of the matrix to enable the above comparisons and replace 0's with 1 in the z vector when the >= condition is satisfied. Any help in writing this loop would be much appreciated! Thanks.

I tried this for a 3x3 matrix but it is giving an error (Error in mat1[i, j + 1] : subscript out of bounds)

mat1 <- matrix(1:9, nrow=3, byrow = TRUE)
z<-rep(0,9)
for(row in 1:nrow(mat1)) {
for(col in 1:ncol(mat1)) {
if(mat1[i,j+1]>=mat1[i,j])
z[i]=1
}
}

Without seeing any logic, I can see: you did not define i and j. Rather you define row and col in the loop. Please use row and col instead of i and j. But, still the code has the problem (if else structure and out of index).

Hi,

I have revised the code taking into account your comments. I am not sure understand the if else structure bit. When I run the following piece of code, it works but does not give the desired result. The break structure has been put because I want comparisons to stop when the column number exceeds the total number of columns in the matrix (this is to avoid the subscript out of bounds error). Any help would be appreciated - I am new to R. Thanks.

for(row in 1:nrow(mat1)) {
for(col in 1:ncol(mat1)) {
if(col+1 > ncol(mat1)) {
break
}
if(mat1[row,col+1]>=mat1[row,col])
z[i]=1
}
}

This is specific to the 3x3 case

test_rel <- function(x) {
  holder <- matrix(, nrow = 3, ncol = 3)
  holder[1,] = x[,2] >= x[,1]
  holder[2,] = x[,3] >= x[,1]
  holder[3,] = x[,3] >= x[,2]
  return(holder)
}

mat <- matrix(1:9, nrow=3, byrow = TRUE)

mat
#>      [,1] [,2] [,3]
#> [1,]    1    2    3
#> [2,]    4    5    6
#> [3,]    7    8    9

test_rel(mat)
#>      [,1] [,2] [,3]
#> [1,] TRUE TRUE TRUE
#> [2,] TRUE TRUE TRUE
#> [3,] TRUE TRUE TRUE

# more interesting case

mat <- matrix(sample(1:9,9), nrow = 3, ncol = 3)

mat
#>      [,1] [,2] [,3]
#> [1,]    3    5    8
#> [2,]    7    9    6
#> [3,]    2    4    1

test_rel(mat)
#>      [,1]  [,2]  [,3]
#> [1,] TRUE  TRUE  TRUE
#> [2,] TRUE FALSE FALSE
#> [3,] TRUE FALSE FALSE

To generalize to the NxN case, a bit of metaprogramming can take N and generate a function appropriately expanded.

Thanks a lot!! Is there a way to generalize this? I want to run this code for large square matrices. Thanks

Also, in the function, I would probably write

test_rel <- function(x) {
  holder <- matrix(, nrow = 3, ncol = 3)
  holder[,1] = x[,2] >= x[,1]
  holder[,2] = x[,3] >= x[,2]
  holder[,3] = x[,3] >= x[,1]
  return(holder)
}

My edit crossed your question.

Every R problem can be thought of with advantage as the interaction of three objects— an existing object, x , a desired object,y , and a function, f, that will return a value of y given x as an argument. In other words, school algebra— f(x) = y. Any of the objects can be composites.

Here we have a square matrix as x. We might want to begin with checking that it is square

is_square <- function(x) dim(x)[1] ==- dim(x)[2]

and fold that into the workflow.

Next, for y we want an empty matrix of like dimension that we can provision as the function's holder object by

holder <- matrix(, nrow = ,dim(x)[1],  ncol = dim[1])

In the interior of test_rel, the assignments to holder would need to be sized accordingly, and the logic of the indexing of the comparison worked out.

Glad to work this with you. Take the first cut?

Hi,

Thanks for your help. I want to point out two things:

  1. First, in your function for checking whether the matrix is square, you have a negative sign before dim(x) [2] which probably should not be present (i.e, the function should read
    is_square <- function(x) dim(x)[1] == dim(x)[2]

  2. I do not want to start with a holder object as a matrix. This is the reason - let's say we have a 4X4 matrix instead of a 3X3 with the following entires:

a11 a12 a13 a14
a21 a22 a23 a24
a31 a32 a33 a34
a41 a42 a43 a44

For each row in this 4x4 matrix, there would be 6 comparisons. Let's consider row 1:
a11 with a12
a11 with a13
a11 with a14
a12 with a13
a12 with a14
a13 with a14

and hence a total of 24 comparisons (6 comparisons per row times 3 rows). I had mentioned initially that in each row, a successive element has to be compared with the preceding element (to see if it is >=). Now if I use a 4x4 matrix as a holder, it would not work out since there are 6 comparisons to be made per row. It is hence better to save the comparison result as a vector (taking the value 1 if the succeeding element is >= to the preceding element and 0 otherwise). This is what I was trying to do in my loop earlier but that has some error where I need help!!

Right, typo.

So, we need a function to generate the number of comparisons to be made for a square matrix of dim(N,N). How would we do that?

The number of comparisons to be made in a square matrix of dimension (N,N) = N^2*(N-1)/2

So for a 3x3 matrix, number of comparisons = 9*(3-1)/2 = 9
and 4X4 matrix, number of comparisons = 16*(4-1)/2 = 24

So this is the function for comparisons
comparisons <- function(x) ((dim(x)[1] ^ 2)*(dim(x)[1] - 1))/2

Now how do I go about using this to store values for comparisons from an NXN matrix. Any thoughts?

OK, thanks. I'm going to set aside the order of comparisons (third column vs second as opposed to third vs first) and work on using combn(n,2) as a starting point. I may be a while.

Hi @Yarnabrina, thanks for your help. I am actually comparing columns and not rows and that was a mistake on my part initially. I am providing a real 3x3 matrix example which would have 9 comparisons (a 5X5 matrix example would have 50 comparisons to be made and that is a lot to write here). You can let me know if it is helpful or not

    [,1] [,2] [,3]

[1,] 1 4 5
[2,] 7 6 10
[3,] 3 11 12

Total Comparisons to be made = N^2*(N-1)/2 = 9 (since N=3 in a 3x3 matrix)

When I say "comparison", I mean if every succeeding number in each column is greater than or equal to the number in the preceding column.

Let me follow the test_rel function given by @technocrat with the change I made to it since I am comparing columns.

test_rel <- function(x) {
holder <- matrix(, nrow = 3, ncol = 3)
holder[,1] = x[,2] >= x[,1]
holder[,2] = x[,3] >= x[,2]
holder[,3] = x[,3] >= x[,1]
return(holder)
}

Sample Output:

       [,1]      [,2]     [,3]

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

I will just explain one of the entries in the output so that it is clear: a21 above is FALSE because a22 in sample input was 6 which is less than 7 (=a21). Now I understand that this is possibly generalizable by for loops but I am not sure how to proceed since I am new to R and mostly to writing loops. I do understand that I start with a placeholder vector which will be equal to the total number of comparisons:
comparisons <- function(x) ((dim(x)[1] ^ 2)*(dim(x)[1] - 1))/2
Initially set all values to zero in comparisons and then count all TRUE occurrences as 1 and FALSE occurrences (when the condition is not satisfied) as 0. Any help on how to proceed would be appreciated. Thanks

A 4x4 case makes more sense since it shows the difference between columns in input matrix and comparisons between expected columns
The way you originally posed the requirements was oversimplified compared to your later exposition.

Hi @nirgrahamuk , I see your point. The reason I did not provide a 4x4 example was because the placeholder that I currently have is in terms of a matrix and 4x4 case will have 4 combine 2 = 24 comparisons, 6 for each row. So there are more comparisons to be made in each row (6) than there are places to be filled in each row (4). If I can set the placeholder as a vector in the above function which is equal to number of comparisons to be made, then I can fill it up with 1s (representing TRUE) and 0s (representing FALSE). Let me still try to give a sample input and discuss a sample output

Sample Input (4x4 matrix)

1 4 8 7
8 5 5 6
7 2 3 12
4 3 4 8

Now each row will have 6 comparisons. Let me consider first row. In the first row, I need to compare entry in a succeeding column with an entry in a preceding column, as in:

a11 with a12 (1 with 4) - returns TRUE since 4 >= 1
a11 with a13 (1 with 8) - returns TRUE since 8 >=1
a11 with a14 (1 with 7)- returns TRUE since 7 >=1
a12 with a13 (4 with 8)- returns TRUE since 8 >= 4
a12 with a14 (4 with 7)- returns TRUE since 7>=4
a13 with a14 (8 with 7)- returns FALSE since 7 <8

I hope this was clear. Thanks

Are you after something like this?

sample_data <- matrix(
  data = c(
    1, 4, 8, 7,
    8, 5, 5, 6,
    7, 2, 3, 12,
    4, 3, 4, 8
  ),
  nrow = 4,
  byrow = TRUE
)

t(x = apply(
  X = sample_data,
  MARGIN = 1,
  FUN = function(row_data) {
    combn(
      x = row_data,
      m = 2,
      FUN = function(pair_data) pair_data[1] <= pair_data[2]
    )
  }
))
#>       [,1]  [,2]  [,3] [,4] [,5]  [,6]
#> [1,]  TRUE  TRUE  TRUE TRUE TRUE FALSE
#> [2,] FALSE FALSE FALSE TRUE TRUE  TRUE
#> [3,] FALSE FALSE  TRUE TRUE TRUE  TRUE
#> [4,] FALSE  TRUE  TRUE TRUE TRUE  TRUE

If this is what you want, this is probably what Richard suggested before:

But I think it'll always ensure order. First, all comparisons with first element, then with second element etc. up to \frac{n \times (n - 1)}{2} for each of the n rows.

2 Likes

@Yarnabrina Thanks a lot! I checked it for various values and various dimensions of the square matrix and it works.

@Yarnabrina

Yeah, I got off on a false foot by thinking row-wise. I suppose that if I had grown up reading top to bottom instead of left to right that I'd have the column vector orientation that makes

mat[,n] >= mat[,n-1]

seem more natural.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.