#install.packages("neuralnet")
#install.packages("datasets")
#install.packages("boot")
#install.packages("MASS")
library(neuralnet)
library(datasets)
library(MASS)

Crabs Dataset Neural Network

We have a dataset of 200 rows and 8 columns, describing 5 morphological measurements on 50 crabs each of two color forms and both sexes, of the species Purple Rock Crab (Leptograpsus variegatus)

We want to try using neural networks to classify crab color based on variables like sex, frontal lobe size, rear width, body depth, and carapace width/length.

Set-up

data(crabs)
sum(is.na(crabs)) #No NAs- good sign. Can't move forward with NAs
## [1] 0
set.seed(2)
crabs$sp <- as.numeric(crabs$sp)-1
crabs$sex <- as.numeric(crabs$sex) -1

# Create Vector of Column Max and Min Values
maxs <- apply(crabs[,4:8], 2, max)
mins <- apply(crabs[,4:8], 2, min)

# Use scale() and convert the resulting matrix to a data frame
scaled.data <- as.data.frame(scale(crabs[,4:8],center = mins, scale = maxs - mins))
scaled.data <- cbind(crabs[,1:2], scaled.data)
# Check out results
print(head(scaled.data,2))
##   sp sex         FL         RW         CL         CW         BD
## 1  0   1 0.05660377 0.01459854 0.04255319 0.05066667 0.05806452
## 2  0   1 0.10062893 0.08759124 0.10334347 0.09866667 0.08387097
#Testing and training
splitsize <- floor(0.7*nrow(scaled.data)) #trying a 70-30 training-testing split
train_ind <- sample(seq_len(nrow(scaled.data)), size= splitsize)

trainset <- scaled.data[train_ind, ]
testset <- scaled.data[-train_ind, ]
#Neural network
nn <- neuralnet(sp ~ sex + FL + RW + CL + CW + BD, data = trainset,
                hidden=c(4),linear.output=FALSE)

The neuralnet() function uses the backpropagation method to build a feed-forward neural network. Notice that we scaled our data in the beginning!

# Compute Predictions off Test Set
predicted.nn.values <- compute(nn,testset[2:7])

# Check out net.result
print(head(predicted.nn.values$net.result))
##                [,1]
## 1  0.05224296806207
## 4  0.00878216904593
## 5  0.03078946478755
## 7  0.01525384492913
## 8  0.00880931999641
## 11 0.00004734057429
predicted.nn.values$net.result <- sapply(predicted.nn.values$net.result,
                                         round,digits=0)

The Neural Network: does it work?

#Let's look at the neural network, and its confusion matrix
table(testset$sp, predicted.nn.values$net.result)
##    
##      0  1
##   0 38  0
##   1  0 22
plot(nn)

The black lines represent connections and weights at each layer, while the blue lines represent the bias term added at each step. Looking at the neural network output and the confusion matrix, we can see that the model did a good job at classifying crab color based on the data.

#Predicting sp using the model
pr.nn_ <- predicted.nn.values$net.result*(max(scaled.data$sp)-
                              min(scaled.data$sp))+min(scaled.data$sp)
test.r <- (testset$sp)*(max(scaled.data$sp)-min(scaled.data$sp))+min(scaled.data$sp)
MSE.nn <- sum((test.r - pr.nn_)^2)/nrow(testset)
print(MSE.nn)
## [1] 0
#plot

plot(testset$sp,pr.nn_,col='red',main='Real vs predicted NN',pch=18,cex=0.7)
abline(0,1,lwd=2)
legend('bottomright',legend='NN',pch=18,col='red', bty='n')

This single-layer neural network does a pretty good job of predicting crab color based on the data. We saw in the confusion matrix that it accurately classified each type of crab, and in these plots we can see that the neural network is able to precisely predict crab color.

10-fold Cross Validation

#10-fold cross-validation
library(boot)
library(plyr) 
set.seed(200)
#MSE for Neural Net
cv.error <- NULL
k <- 10

for(i in 1:k){
  index <- sample(1:nrow(scaled.data),round(0.7*nrow(scaled.data)))
  trainset.cv <- scaled.data[index, ]
  testset.cv <- scaled.data[-index, ]
  
  nn1 <- neuralnet(sp ~ sex + FL + RW + CL + CW + BD,
                  data=trainset.cv,hidden=c(4,4,4),linear.output=FALSE)

  #Computes neural network outputs  
  pr.nn1 <- compute(nn1,testset.cv[,2:7])
  pr.nn1 <- pr.nn1$net.result*(max(scaled.data$sp)
                             -min(scaled.data$sp))+min(scaled.data$sp)
  
  test.cv.r <- (testset.cv$sp)*(max(scaled.data$sp)
                                -min(scaled.data$sp)) + min(scaled.data$sp)
  #MSE for NN
  cv.error[i] <- sum((test.cv.r - pr.nn1)^2)/nrow(testset.cv)
}

#Average of MSE for 10 iterations
mse.nn1 <- mean(cv.error)
print(mse.nn1)
## [1] 0.003184963087

This MSE is still fairly close to 0, the neural network seems to be a good method for prediction based on cross-validation as well.