Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change matrix entries using conditional if in R

I have this example matrix and I want to change the entries of the matrix with "YES" or "NO" based on a conditional if statement.

a<-c(5,1,0,3,2,0.6,1.6,7,9,0)
b<-c(11,0,1,18,11,11,0,13,20,10)
c<-c(10,20,0.7,0.8,0.3,0.4,0,0.9,1,1)

MAT<-cbind(a,b,c)
MAT

for (i in 1:nrow(MAT)){
  for (j in 1:ncol(MAT)){
  if (MAT[i,j]>5){
    MAT[i,j]="YES"
    } else {
    MAT[i,j]="NO"
    }
  }
}
print(MAT)

The output I got is like this and its wrong. Please help tell me what's wrong and how to fix it?

      a     b    c   
[1,] "NO"  "NO" "NO"
[2,] "NO"  "NO" "NO"
[3,] "NO"  "NO" "NO"
[4,] "NO"  "NO" "NO"
[5,] "NO"  "NO" "NO"
[6,] "NO"  "NO" "NO"
[7,] "NO"  "NO" "NO"
[8,] "YES" "NO" "NO"
[9,] "YES" "NO" "NO"
[10,] "NO"  "NO" "NO"
like image 206
MK Huda Avatar asked Aug 15 '21 11:08

MK Huda


2 Answers

You do not need loops here. Just use the whole matrix in your call to x>5

ifelse(MAT>5, "YES", "NO")

This will do the logical operation over the entire matrix. However, the output will be a vector, which is basically the resulting logical matrix, but stripped from its dim atribute.

You can reassign the VALUES from the output of ifelse() while keeping the STRUCTURE of MAT by using the empty brackets [], as in:

MAT[]<-ifelse(MAT>5, "YES", "NO")
like image 135
GuedesBF Avatar answered Oct 13 '22 01:10

GuedesBF


Reason of Failure

The reason you failed in your attempt comes from this part:

  if (MAT[i,j]>5){
    MAT[i,j]="YES"
    } else {
    MAT[i,j]="NO"
    }
  }

You should have be aware of that MAT is numerical, but you are assigning characters to MAT with in if...else... statement, which will make MAT converted to a character matrix. In this case, when you run MAT[i,j] > 5, you are comparing a character with a numeric value, e.g., "18" > 5, which returns an undesired FALSE.


Workaround

A workaround is using another variable to store the values after if...else..., instead of replacing values in MAT:

a <- c(5, 1, 0, 3, 2, 0.6, 1.6, 7, 9, 0)
b <- c(11, 0, 1, 18, 11, 11, 0, 13, 20, 10)
c <- c(10, 20, 0.7, 0.8, 0.3, 0.4, 0, 0.9, 1, 1)

MAT <- cbind(a, b, c)
out <- MAT

for (i in 1:nrow(MAT)) {
  for (j in 1:ncol(MAT)) {
    if (MAT[i, j] > 5) {
      out[i, j] <- "YES"
    } else {
      out[i, j] <- "NO"
    }
  }
}

such that

> out
      a     b     c
 [1,] "NO"  "YES" "YES"
 [2,] "NO"  "NO"  "YES"
 [3,] "NO"  "NO"  "NO"
 [4,] "NO"  "YES" "NO"
 [5,] "NO"  "YES" "NO"
 [6,] "NO"  "YES" "NO"
 [7,] "NO"  "NO"  "NO"
 [8,] "YES" "YES" "NO"
 [9,] "YES" "YES" "NO"
[10,] "NO"  "YES" "NO"

Alternative

There are already many answers to this question, and below is another base R option

> `dim<-`(as.character(factor(MAT > 5, labels = c("NO", "YES"))), dim(MAT))
      [,1]  [,2]  [,3]
 [1,] "NO"  "YES" "YES"
 [2,] "NO"  "NO"  "YES"
 [3,] "NO"  "NO"  "NO"
 [4,] "NO"  "YES" "NO"
 [5,] "NO"  "YES" "NO"
 [6,] "NO"  "YES" "NO"
 [7,] "NO"  "NO"  "NO"
 [8,] "YES" "YES" "NO"
 [9,] "YES" "YES" "NO"
[10,] "NO"  "YES" "NO"
like image 32
ThomasIsCoding Avatar answered Oct 13 '22 02:10

ThomasIsCoding