-2

I can't get a for loop to assign the string 'NA' when none of the other conditions are met.

This is what I've tried...

Height <- c(1.6,3.4,0.42,n/a, 0.5,n/a,1.5,0,n/a,22.0)
Height <- matrix(Height)  

h_cat <- matrix(, nrow = length(Height), ncol = 1)
for (i in 1:length(Height)){
  if (Height[i]==0)
    h_cat[i] <- 'NA'
  if (Height[i]>0 & Height[i]<2)
    print(Height[i])
    h_cat[i] <- '0-2 m'
    #print(h_cat[i])
  if (Height[i]>=2 & Height[i]<5)
    h_cat[i] <- '2-5 m'
  if (Height[i]>=5 & Height[i]<10)
    h_cat[i] <- '5-10 m'
  if (Height[i]>=10)
    h_cat[i] <- '>10 m'
  else
    h_cat[i] <- 'NA'
}

I had a go with is.na() but no luck either.

Update

Sorry that was rushed. Data added.

Josh J
  • 395
  • 1
  • 3
  • 13

2 Answers2

2

There are two main problems with the current code.

  1. First can be exemplified by NA == 0, which returns NA. Thus you can only use the if function on the non-NA entries: which(!is.na(Height)).
  2. The logic of your if-else construction is not working as what seems to be the intention.

The below I believe achieves your intentions:

# Data needs to be numeric to check with ">"
Height[Height == "n/a", ] <- NA
Height <- as.numeric(Height)

h_cat <- matrix(, nrow = length(Height), ncol = 1)

# Can't have NA in logical tests
non_na_entries <- which(!is.na(Height))
for (i in non_na_entries) {
  if (Height[i] == 0) {
    h_cat[i] <- NA
  } else if (Height[i] > 0 & Height[i] < 2) {
    h_cat[i] <- '0-2 m'
  } else if (Height[i] >= 2 & Height[i] < 5) {
    h_cat[i] <- '2-5 m'
  } else if (Height[i] >= 5 & Height[i] < 10) {
    h_cat[i] <- '5-10 m'
  } else if (Height[i] >= 10) {
    h_cat[i] <- '>10 m'
  } else
    h_cat[i] <- NA
}

    h_cat

     [,1]   
 [1,] "0-2 m"
 [2,] "2-5 m"
 [3,] "0-2 m"
 [4,] NA     
 [5,] "0-2 m"
 [6,] NA     
 [7,] "0-2 m"
 [8,] NA     
 [9,] NA     
[10,] ">10 m"
s_baldur
  • 29,441
  • 4
  • 36
  • 69
0

There are several problems with your code. Two of them were addressed by snoram. You need to substitute NA for 'n/a', and you don't need Height to be a matrix. To make the code that follows a complete answer, I'll repeat the NA part.

Height <- c(1.6,3.4,0.42,n/a, 0.5,n/a,1.5,0,n/a,22.0)
Height[Height == "n/a"] <- NA

Now, an alternative to a complicated if/else is, like many have said, cut. Since it returns an object of class factor we'll need to recode its return value. To do that, I'll use a function from package dplyr.

library(dplyr)

h_cat <- cut(Height, c(0, 2, 5, 10, Inf))
h_cat[Height == 0] <- NA
h_cat <- recode_factor(h_cat,
                 '(0,2]' = '0-2 m',
                 '(2,5]' = '2-5 m',
                 '(5,10]' = '5-10 m',
                 '(10,Inf]' = '>10 m')
h_cat <- matrix(as.character(h_cat), ncol = 1)
h_cat

I believe that this is much simpler and readable. Neater. If you ever have to come back to this code in the future, you'll probably find it much easier to maintain.

Rui Barradas
  • 70,273
  • 8
  • 34
  • 66