Neural Networks in R

A neural network is a machine-learning algorithm that makes decisions in a manner similar to our human brains. It uses interconnected nodes (neurons) in a layered structure and has an adaptive system that computers also use, which learn from their mistakes and improve continuously.

Neural networks can handle complicated problems such as summarizing documents, or recognizing faces, with generally greater accuracy than more other algorithms.

A visualization of the Neural Network structure (Ramos D. 2018. SmartSheet.)

A visualization of the Neural Network structure (Ramos D. 2018. SmartSheet.)

Packages

In this chapter, we’ll learn how to create neural networks in R, utilizing the neuralnet package!

We’ll use the iris dataset for our examples. The details of it can be found in the iris dataset overview. First, we’ll want to make sure our data is ready for model fitting.

library(MASS)
data(iris)
# First check that no datapoint is missing
apply(iris, 2, function(x) sum(is.na(x)))
apply(iris, 2, function(x) sum(is.na(x)))
Sepal.Length 0
Sepal.Width 0
Petal.Length 0
Petal.Width 0
Species 0

The results for all of the categories returns as zero, which means there’s no missing data. Let’s proceed by randomly splitting the data into training and testing sets, which we’ll fit a linear regression and MLP model on.

Data Partitioning

The sample(x, size) function outputs a vector of the specified size from randomly selected samples in vector x. By default, the sampling is without replacement: the selected index is essentially a random vector of indeces.

  • iris[index, ]: extract all rows from the full dataset with the selected row indices.
  • iris[-index,]: extract all the rows from the full dataset that were not the selected row indices.
# data spliting
set.seed(310)
index = sample(1:nrow(iris), round(0.7*nrow(iris)), replace=F)
train = iris[index,]
test = iris[-index,]
dim(train)
[1] 105   5
dim(test)
[1] 45  5

Training Models using neuralnet

To build neural network models in R, we’ll need to use the neuralnet package. The neuralnet(formula, data, hidden, linear.output) function has these following parameters we’ll use:

  • formula: y ~ predictors, the formula follows the same format as most other modelling functions in R.
  • data: a dataframe containing the variables listed in formula.
  • hidden: a vector of integers specifying the number of hidden neurons in each layer.
  • linear.output: by default, this is set to FALSE. We’ll keep it this way.
# install.packages("neuralnet")
library(neuralnet)
nnet = neuralnet(Species~., train, hidden = c(4,3), linear.output = FALSE)
plot(nnet,rep="best")

To obtain the outputs from running nnet on our test data, we’ll need to use the compute() function provided by neuralnet. (Note that you may need to write it was neuralnet::compute() to let R know that we’re overriding any native compute() functions.)

ypred = neuralnet::compute(nnet, test[,-5])
yhat = ypred$net.result
head(yhat)
   [,1]        [,2]         [,3]
1     1 0.003676943 1.926207e-09
6     1 0.003676943 1.926207e-09
7     1 0.003676943 1.926207e-09
11    1 0.003676943 1.926207e-09
17    1 0.003676943 1.926207e-09
22    1 0.003676943 1.926207e-09

The prediction results above show the probability of each class. We’ll have to extract the class with the highest probability values, as our final predicted result:

c("setosa","versicolor","virginica")[yhat[1,]==max(yhat[1,])]
sp = c("setosa","versicolor","virginica")
tt = apply(yhat,1,function(x) sp[x==max(x)])
tt
[1] "setosa"
tt
1 setosa
6 setosa
7 setosa
11 setosa
17 setosa
22 setosa
24 setosa
27 setosa
32 setosa
33 setosa
35 setosa
38 setosa
47 setosa
48 setosa
52 versicolor
53 versicolor
59 versicolor
61 versicolor
63 versicolor
64 versicolor
69 versicolor
71 virginica
74 versicolor
75 versicolor
79 versicolor
80 versicolor
82 versicolor
84 virginica
87 versicolor
89 versicolor
90 versicolor
97 versicolor
106 virginica
108 virginica
115 virginica
117 virginica
118 virginica
120 virginica
124 virginica
125 virginica
127 virginica
128 virginica
136 virginica
139 virginica
146 virginica

This outputs the prediction for each observation in the testing set. The index numbers on the left are the indices of each observation in the full Iris dataset, and the tt value is the final prediction for each observation.

Accuracy scores

We can view the accuracy of our neural network model by generating a confusion matrix:

yclass = apply(yhat,1,function(x) sp[x==max(x)])
# Same as: yclass= sp[ apply(yhat, 1, which.max) ]
table(test$Species, yclass)
setosa versicolor virginica
setosa 14 0 0
versicolor 0 16 2
virginica 0 0 13
print("Accuracy on testing dataset:")
mean(test$Species==yclass)
[1] "Accuracy on testing dataset:"
[1] 0.9555556

For a first attempt, a 95.6% accuracy rate is quite good compared to what we’ve gotten in the past with different models. Recall that our K-means model had an accuracy rate of 89% on its first attempt with the Iris dataset.

Training a second MLP model

Let’s explore what else neuralnet() has to offer, by starting with some more parameters:

  • rep: the number of repetitions used for the neural network’s training.
  • err.fct: a differentiable function that is used for the calculation of the error. Alternatively, the strings "sse" and "ce" which stand for the sum of squared errors and the cross-entropy can be used.
  • lifesign: a string specifying hwo much the function will print during the calculation of the neural network. (none, minimal, or full.)
  • stepmax: the maximum steps for the training of the neural network. Reaching this maximum leads to a hard stop of the neural network’s training process.
  • threshold: a numeric value specifying the theshold for the partial derivatives of the error function as a stopping criteria.
# Let's train another MLP model
iris.net <- neuralnet(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, 
                      data=train, 
                      hidden=c(5,6), 
                      rep = 3, 
                      err.fct = "ce", 
                      linear.output = F, 
                      lifesign = "minimal", 
                      stepmax = 1000000,
                      threshold = 0.001)
hidden: 5, 6    thresh: 0.001    rep: 1/3    steps:    3035 error: 5e-05    time: 0.7 secs
hidden: 5, 6    thresh: 0.001    rep: 2/3    steps:    1108 error: 3e-05    time: 0.17 secs
hidden: 5, 6    thresh: 0.001    rep: 3/3    steps:     808 error: 1e-04    time: 0.14 secs
plot(iris.net, rep = 'best')

Let’s see what accuracy score our second neural network model has:

iris.pred = compute(iris.net, test[-5:-8])
idx = apply(iris.pred$net.result, 1, which.max)
preds = c('setosa', 'versicolor', 'virginica')[idx]
table(preds, test$Species)
setosa versicolor virginica
setosa 14 0 0
versicolor 0 16 0
virginica 0 2 13
print("Accuracy on the testing data set:")
mean(preds==test$Species)
[1] "Accuracy on the testing data set:"
[1] 0.9555556