I'm new to R and am experiencing a problem properly populating a column of data within a data frame. I'm populating two columns (P_Score and P_Class) based on another column (P_Value) using a series of if / else if statements.
i<- 0
nr<- nrow(myData)
while(i<nr){
i<-1+i
if(toString(myData$P_Value[i])=="NA"){ myData$P_Score[i] <- myData$P_Value[i]
} else if (as.numeric(toString(myData$P_Value[i]))<5){
myData$P_Score[i] <- 1; myData$P_Class[i] <- "Minimal Depression";
} else if (as.numeric(toString(myData$P_Value[i]))<10){
myData$P_Score[i] <- 2; myData$P_Class[i] <- "Mild Depression";
} else if (as.numeric(toString(myData$P_Value[i]))<15){
myData$P_Score[i] <- 3; myData$P_Class[i] <- "Moderate Depression";
} else if (as.numeric(toString(myData$P_Value[i]))<20){
myData$P_Score[i] <- 4; myData$P_Class[i] <- "Moderate-Severe Depression";
} else
myData$P_Score[i] <- 5; myData$P_Class[i] <- "Severe Depression";
}
However, this is not giving me my desired result, and instead I wind up with this:
P_Value P_Score P_Class
4 1 Severe Depression
25 5 Severe Depression
8 2 Severe Depression
13 3 Severe Depression
17 4 Severe Depression
1 1 Severe Depression
12 3 Severe Depression
So the P_Score is populating just fine, but the P_Class is always defaulting to "Severe Depression". I must be having some issue executing multiple statements based off of 1 if condition, but I can't figure out what I'm doing wrong. I have read elsewhere as long as you put semicolons after the statements both should work, but that's clearly not working.
I have also tried spacing out the commands like this:
} else if (as.numeric(toString(myData$P_Value[i]))<5){
myData$P_Score[i] <- 1
myData$P_Class[i] <- "Minimal Depression"
But that does not seem to work either. Please help!
3 Answers
R has a function for this, there is no need for any loops. Please read ?cut:
Set up example
myData
# P_Value
# 1 4
# 2 25
# 3 8
# 4 13
# 5 17
# 6 1
# 7 12
# 8 NA
grps <- cut(myData$P_Value,
breaks=c(-Inf, 5, 10, 15, 20, Inf),
labels=c("Min Dep", "Mild Dep", "Mod Dep", "Mod-Sev Dep", "Sev Dep"))
With the groups created, we can make a Score and Class column from it
myData$P_Score <- as.numeric(grps)
myData$P_Class <- grps
myData
# P_Value P_Score P_Class
# 1 4 1 Min Dep
# 2 25 5 Sev Dep
# 3 8 2 Mild Dep
# 4 13 3 Mod Dep
# 5 17 4 Mod-Sev Dep
# 6 1 1 Min Dep
# 7 12 3 Mod Dep
# 8 NA NA <NA>
You should use:
if (<condition>){
} else {
if(<condition>){
} else {
}
}
Or:
ifelse(<condition>,
ifelse(<condition>, <yes>, <no>)
)
So, in my opinion, you missed the {} after your else command.
The Problem with your code is, that it always gives R the comand myData$P_Class[i] <- "Severe Depression";. As an example check out this code:
test <- 12
ret <- NA
if(test < 5){
ret <- 1; print("Minimal");
}else if(test < 10){
ret <- 2; print ("Mild");
}else if(test < 15){
ret <- 3; print ("Moderate");
}else if(test < 20){
ret <- 4; print ("Moderate-Severe");
}else ret<- 5;print("Severe Depression");
You should write instead for the last line else{myData$P_Score[i] <- 5; myData$P_Class[i] <- "Severe Depression";}. In doubt, always use more brackets than less. Here is my more reduced code (and I bet, it even gets smarter).
for(i in 1:nrow(myData)){
tmp <- as.numeric(toString(myData$P_Value[i]))
if(is.na(myData$P_Value[i])){
myData$P_Score[i] <- myData$P_Value[i]
} else if (tmp < 5){
myData$P_Score[i] <- 1
myData$P_Class[i] <- "Minimal Depression"
} else if (tmp < 10){
myData$P_Score[i] <- 2
myData$P_Class[i] <- "Mild Depression"
} else if (tmp < 15){
myData$P_Score[i] <- 3
myData$P_Class[i] <- "Moderate Depression"
} else if (tmp < 20){
myData$P_Score[i] <- 4
myData$P_Class[i] <- "Moderate-Severe Depression"
} else{
myData$P_Score[i] <- 5
myData$P_Class[i] <- "Severe Depression"
}
}