2

I am having trouble with a loop I am creating. My intention is that the loop will see where a value falls and give that value another name. Here is an example of what I am trying to do:

a<-rnorm(10,0,1)
b<-rnorm(10,0,1)

testing<-data.frame(a,b)

testing2<-testing
for (i in 1:nrow(testing2)){
  for (j in 1:ncol(testing2)){
    if (testing2[i,j]>1) testing2[i,j]<-"More"
    else if (testing2[i,j]<(-1)) testing2[i,j]<-"Less"
    else testing2[i,j]<-"Same"
  }
}

When I look at testing2 and compare it to testing, it does not match what it should be doing. "More" seems to work, but it gets mixed up between "Less" and "Same".

Thomas
  • 43,637
  • 12
  • 109
  • 140
user3379798
  • 417
  • 1
  • 4
  • 7

3 Answers3

5

No need for a (nested) loop, use the vectorised ifelse instead:

testing = ifelse(testing > 1, 'More', ifelse(testing < -1, 'Less', 'Same'))
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
5

cut comes to mind as an obvious candidate here. Since you need to apply it across multiple columns, you can use lapply as follows:

x <- testing
x[] <- lapply(testing, cut, breaks=c(-Inf, -1, 1, Inf), 
              labels=c("less", "same", "more"))
x

^^edited with refinements from the comments ;-)

Or with as.matrix instead of lapply...

x <- cut(as.matrix(testing), c(-Inf, -1, 1, Inf), 
         labels=c("less", "same", "more"))
dim(x) <- dim(testing)
A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485
1

As suggested, there are better ways of doing this. But coming back to your code, you are messing things up by assigning a character to numeric type.

In R data.frame the columns have the same type. Therefore once you assign a character, the entire column type becomes character.

You can verify this by calling sapply(testing2, class) before and after the for loops

Nishanth
  • 6,932
  • 5
  • 26
  • 38