-1

I wondering why my first if statement returns Error when my input data is an object of class numeric?

I have clearly stated for the first if statement to only turn on IF the data class is "data.frame", but when data class is numeric, this first if statement return an error! am I missing anything here?

Update:

I have changed instances of & to && but when data is a data.frame, the function doesn't produce any output? For example, run: standard(mtcars)

standard <- function(data){

  if(class(data) == "data.frame" && ncol(data) > 1){ 

  data[paste0(names(data), ".s")] <- scale(data)
  data
}

 if(class(data) == "data.frame" && ncol(data) == 1){

 colnames(data) <- paste0(names(data), ".s") 
 data <- scale(data)
 data
}  

 if(class(data) != "data.frame"){

d <- as.data.frame(data)  
colnames(d) <- paste0("Var", ncol(d), ".s")
data <- scale(d)
data
   }
}
###### EXAMPLES: #######
standard(mtcars[,2])   ##Problem: `Error in if(class(data) == "data.frame" & ncol(data) > 1)`
standard(mtcars["wt"]) ## OK
standard(mtcars)       ## after UPDATE, doesn't give any output
rnorouzian
  • 7,397
  • 5
  • 27
  • 72

2 Answers2

2

am I missing anything here?

& evaluate both elements while && does not

FALSE && stop("boh")
#R> [1] FALSE
TRUE  && stop("boh")
#R> Error: boh
FALSE &  stop("boh")
#R> Error: boh

See help("Logic")

& and && indicate logical AND and | and || indicate logical OR. The shorter form performs elementwise comparisons in much the same way as arithmetic operators. The longer form evaluates left to right examining only the first element of each vector. Evaluation proceeds only until the result is determined.


After your edits

You do not get any results because you do not call return or use if else. See help("function") and help("if"). Here is a small example

f1 <- function(x){
  if(x < 0){
    x <- -1
    x
  }

  if(x > 0){
    x <- 1
    x
  }
}
f1(-1)

f2 <- function(x){
  if(x < 0){
    x <- -1
    x
  }
  else if(x > 0){
    x <- 1
    x
  }
}
f2(-1)
#R> [1] -1

f3 <- function(x){
  if(x < 0){
    x <- -1
    return(x)
  }

  if(x > 0){
    x <- 1
    return(x)
  }
}
f3(-1)
#R> [1] -1
2

tl;dr you should use && rather than & when doing flow-control, because & always evaluates its second argument, while && short-circuits if the first argument is false. If the argument isn't a data frame (or matrix) then ncol(x) doesn't make sense: see e.g. this question for more information.

Go ahead and unpack it with a simple example.

x <- 1:5

The first part is fine:

class(x)  ## "integer"
class(x)=="data.frame"  ## TRUE

(although note that you have to be careful, because class(x) might be a vector with more than one element: inherits(x,"data.frame") is safer).

The second part causes the problem:

ncol(x) ## NULL (uh-oh)
ncol(x)>1  ## numeric(0) (uh-oh)

Put them together:

class(x)=="data.frame" & ncol(x)>1  ## logical(0)

What does this do?

if (logical(0)) print("hello")

Error in if (logical(0)) print("hello") : argument is of length zero

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • 1
    I think you might not understand what @BenjaminChristofferson and I are trying to say about "short-circuiting". The problem is that `ncol(x)` doesn't make sense if `x` is not a data frame or matrix, so evaluating this argument (and including it in the logical statement) causes trouble [as you found out] – Ben Bolker Mar 17 '18 at 19:28
  • Since it wasn't the scope of your question, I didn't look at the function beyond the first logical statement ... Maybe it would help to put some explicit `return()` statements in. – Ben Bolker Mar 17 '18 at 19:53