0

I have written a function that plots (in both Base R and ggplot) the misclassification rate for various values of K in a KNN classification problem. My problem is that, while Base R plot displays, ggplot graph does not display. When I take the ggplot code out of the function, it works. I'm not sure what I am doing wrong.

Can someone please point out what I am doing wrong?

Code:

library(ISLR)
library(ggplot2)
library(class)

data("Weekly")
train <- (Weekly$Year < 2009)
Weekly.train <- Weekly[ train, ]
Weekly.test <- Weekly[ !train, ]

knn.train.x <- scale( as.data.frame(Weekly$Lag2[train]) )
knn.test.x <- scale( as.data.frame(Weekly$Lag2[!train]) )
train.Direction <- Weekly$Direction[train]
set.seed(1234)

#Function for choosing k in knn
misclassknn <- function(train, test, 
                    response.train, 
                    response.test, 
                    Kmax){ 
  K <- 1:Kmax
  misclass <- numeric(Kmax)
  for( k in K){
    knn.pred <- knn(train,test,response.train, k=k)
    misclass[k] <- mean(knn.pred!=response.test)
  }
  # base R
  plot(c(1, Kmax), c(0, 1), type = "n", 
       main = "Misclassification Rate for K Values",
       xlab = "K", ylab = "Misclassification Rate")
  points(1 : Kmax, misclass, type = "b", pch = 16)

  # ggplot
  df <- data.frame(1 : Kmax, misclass)
  names(df) <- c("misclass", "K")
   ggplot(df, aes(x = misclass, y = K)) + geom_line() + ylim(0, 1) +
    geom_point() + labs( title = "Misclassification Rate for K Values", 
                     y = "Misclassification Rate", x = "K")

  return(list(K = Kmax, misclass = misclass, 
          Kmin = which.min(misclass)))
}

misclassknn(train = knn.train.x, 
        test = knn.test.x, 
        response.train = train.Direction,
        response.test = Weekly$Direction[!train], 
        Kmax = 15)
Soly
  • 155
  • 1
  • 2
  • 9

1 Answers1

3

We take for granted the way plotting works in R. For ggplot it actually returns an object, which is a description for how to build plot. Inside of functions, due to the different scope things aren't displayed like they are in the global scope. Basically you either need to manually tell it to display the plot by wrapping print() or ggplot_build around the ggplot command, or you need to return the object as an output of your function and then call it from the global scope. Essentially you're just forcing it to display the object.

It's common to store the ggplot object with something like

p <- ggplot(etc) + geom_etc() + ...

Now the object p can be built into a graph when you want it to be. You could use print(p) (or ggplot_build(p)) or you could just use p in your main code if it's returned by the function, e.g. return(p).

LachlanO
  • 1,152
  • 8
  • 14