In this project, we will use the data from accelerometers on the belt, forearm, arm, and dumbell of 6 participants to predict the manner in which the exercise was done. This is the “classe” variable in the training set. We will train 4 different models - Decision Trees, Random Forest, Gradient Boosted Trees, and Support Vector Machine - using k-folds cross validation on the training set. We will then predict using a validation set which is randomly selected from the training set, to obtain the accuracy and out of sample error rate. Based on these metrics, we will then decide on the final model to be used to predict the 20 cases on the test set.
Using devices such as Jawbone Up, Nike FuelBand, and Fitbit, it is now possible to collect a large amount of data about personal activity relatively inexpensively. These type of devices are part of the quantified self movement – a group of enthusiasts who take measurements about themselves regularly to improve their health, to find patterns in their behavior, or because they are tech geeks. One thing that people regularly do is quantify how much of a particular activity they do, but they rarely quantify how well they do it.
In this project, my goal will be to use data from accelerometers on the belt, forearm, arm, and dumbell of 6 participants. They were asked to perform barbell lifts correctly and incorrectly in 5 different ways. More information is available from the website here: http://web.archive.org/web/20161224072740/http:/groupware.les.inf.puc-rio.br/har (see the section on the Weight Lifting Exercise Dataset).
The training data for this project are available here: https://d396qusza40orc.cloudfront.net/predmachlearn/pml-training.csv
The test data are available here: https://d396qusza40orc.cloudfront.net/predmachlearn/pml-testing.csv
The data for this project come from this source: http://web.archive.org/web/20161224072740/http:/groupware.les.inf.puc-rio.br/har
First, let’s load the training data and test data.
## Check if the file exists
if (!file.exists("Dataset")) {
dir.create("Dataset")
}
## Load the training data
trainUrl = "https://d396qusza40orc.cloudfront.net/predmachlearn/pml-training.csv"
download.file(trainUrl, destfile = "./Dataset/pml-training.csv")
trainData = read.csv("./Dataset/pml-training.csv")
## Load the test data
testUrl = "https://d396qusza40orc.cloudfront.net/predmachlearn/pml-testing.csv"
download.file(testUrl, destfile = "./Dataset/pml-testing.csv")
testData = read.csv("./Dataset/pml-testing.csv")
dim(trainData)
## [1] 19622 160
dim(testData)
## [1] 20 160
We see that there are 160 variables in both training and test data, with 19622 observations in the training data and 20 observations in the test data.
Let’s remove the unnecessary variables.
## Removing variables which are mostly NA values
trainData <- trainData[, colMeans(is.na(trainData)) < 0.90]
## Removing metadata which are irrelevant to the outcome
trainData <- trainData[, -c(1: 7)]
## Removing near zero variance variables
library(caret)
nzv <- nearZeroVar(trainData)
trainData <- trainData[, -nzv]
dim(trainData)
## [1] 19622 53
Now that we have removed the unnecessary variables, we can now split the training data into a training set and a validation set. The test data will be left alone, and used for prediction after we have selected our final model.
set.seed(1234)
inTrain <- createDataPartition(y = trainData$classe,
p = 0.7, list = FALSE)
## Create training set
training <- trainData[inTrain, ]
## Create validation set
validation <- trainData[-inTrain, ]
dim(training)
## [1] 13737 53
dim(validation)
## [1] 5885 53
We will train 4 different models - Decision Trees, Random Forest, Gradient Boosted Trees, and Support Vector Machine - using k-folds cross validation on the training set. We will then predict using the validation set to obtain the accuracy and out of sample error rate.
Set up control to use 3-fold cross validation on the training set.
control <- trainControl(method = "cv", number = 3, verboseIter = FALSE)
Model:
DT <- train(classe ~ ., data = training, method = "rpart", trControl = control, tuneLength = 5)
library(rattle)
fancyRpartPlot(DT$finalModel)
Prediction:
DT_pred <- predict(DT, newdata = validation)
DT_prediction <- confusionMatrix(DT_pred, factor(validation$classe))
DT_prediction
## Confusion Matrix and Statistics
##
## Reference
## Prediction A B C D E
## A 1519 473 484 451 156
## B 28 355 45 10 130
## C 83 117 423 131 131
## D 40 194 74 372 176
## E 4 0 0 0 489
##
## Overall Statistics
##
## Accuracy : 0.5366
## 95% CI : (0.5238, 0.5494)
## No Information Rate : 0.2845
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.3957
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Statistics by Class:
##
## Class: A Class: B Class: C Class: D Class: E
## Sensitivity 0.9074 0.31168 0.41228 0.38589 0.45194
## Specificity 0.6286 0.95512 0.90492 0.90165 0.99917
## Pos Pred Value 0.4927 0.62500 0.47797 0.43458 0.99189
## Neg Pred Value 0.9447 0.85255 0.87940 0.88228 0.89002
## Prevalence 0.2845 0.19354 0.17434 0.16381 0.18386
## Detection Rate 0.2581 0.06032 0.07188 0.06321 0.08309
## Detection Prevalence 0.5239 0.09652 0.15038 0.14545 0.08377
## Balanced Accuracy 0.7680 0.63340 0.65860 0.64377 0.72555
Model:
RF <- train(classe ~ ., data = training, method = "rf", trControl = control, tuneLength = 5)
Prediction:
RF_pred <- predict(RF, newdata = validation)
RF_prediction <- confusionMatrix(RF_pred, factor(validation$classe))
RF_prediction
## Confusion Matrix and Statistics
##
## Reference
## Prediction A B C D E
## A 1673 4 0 0 0
## B 1 1132 8 0 0
## C 0 3 1016 5 1
## D 0 0 2 958 0
## E 0 0 0 1 1081
##
## Overall Statistics
##
## Accuracy : 0.9958
## 95% CI : (0.9937, 0.9972)
## No Information Rate : 0.2845
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9946
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: A Class: B Class: C Class: D Class: E
## Sensitivity 0.9994 0.9939 0.9903 0.9938 0.9991
## Specificity 0.9991 0.9981 0.9981 0.9996 0.9998
## Pos Pred Value 0.9976 0.9921 0.9912 0.9979 0.9991
## Neg Pred Value 0.9998 0.9985 0.9979 0.9988 0.9998
## Prevalence 0.2845 0.1935 0.1743 0.1638 0.1839
## Detection Rate 0.2843 0.1924 0.1726 0.1628 0.1837
## Detection Prevalence 0.2850 0.1939 0.1742 0.1631 0.1839
## Balanced Accuracy 0.9992 0.9960 0.9942 0.9967 0.9994
Model:
GBM <- train(classe ~ ., data = training, method = "gbm", trControl = control, tuneLength = 5, verbose = FALSE)
Prediction:
GBM_pred <- predict(GBM, newdata = validation)
GBM_prediction <- confusionMatrix(GBM_pred, factor(validation$classe))
GBM_prediction
## Confusion Matrix and Statistics
##
## Reference
## Prediction A B C D E
## A 1671 5 0 0 0
## B 1 1128 15 0 0
## C 2 6 1007 8 4
## D 0 0 4 953 1
## E 0 0 0 3 1077
##
## Overall Statistics
##
## Accuracy : 0.9917
## 95% CI : (0.989, 0.9938)
## No Information Rate : 0.2845
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9895
##
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: A Class: B Class: C Class: D Class: E
## Sensitivity 0.9982 0.9903 0.9815 0.9886 0.9954
## Specificity 0.9988 0.9966 0.9959 0.9990 0.9994
## Pos Pred Value 0.9970 0.9860 0.9805 0.9948 0.9972
## Neg Pred Value 0.9993 0.9977 0.9961 0.9978 0.9990
## Prevalence 0.2845 0.1935 0.1743 0.1638 0.1839
## Detection Rate 0.2839 0.1917 0.1711 0.1619 0.1830
## Detection Prevalence 0.2848 0.1944 0.1745 0.1628 0.1835
## Balanced Accuracy 0.9985 0.9935 0.9887 0.9938 0.9974
Model:
SVM <- train(classe ~ ., data = training, method = "svmLinear", trControl = control)
Prediction:
SVM_pred <- predict(SVM, newdata = validation)
SVM_prediction <- confusionMatrix(SVM_pred, factor(validation$classe))
SVM_prediction
## Confusion Matrix and Statistics
##
## Reference
## Prediction A B C D E
## A 1537 154 79 69 50
## B 29 806 90 46 152
## C 40 81 797 114 69
## D 61 22 32 697 50
## E 7 76 28 38 761
##
## Overall Statistics
##
## Accuracy : 0.7813
## 95% CI : (0.7705, 0.7918)
## No Information Rate : 0.2845
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.722
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Statistics by Class:
##
## Class: A Class: B Class: C Class: D Class: E
## Sensitivity 0.9182 0.7076 0.7768 0.7230 0.7033
## Specificity 0.9164 0.9332 0.9374 0.9665 0.9690
## Pos Pred Value 0.8137 0.7177 0.7239 0.8086 0.8363
## Neg Pred Value 0.9657 0.9301 0.9521 0.9468 0.9355
## Prevalence 0.2845 0.1935 0.1743 0.1638 0.1839
## Detection Rate 0.2612 0.1370 0.1354 0.1184 0.1293
## Detection Prevalence 0.3210 0.1908 0.1871 0.1465 0.1546
## Balanced Accuracy 0.9173 0.8204 0.8571 0.8447 0.8362
Let’s look at the results (accuracy and out of sample error rate) of the 4 models.
## Create matrix with 2 columns and 4 rows
result = round(matrix(data = c(DT_prediction$overall[1], RF_prediction$overall[1], GBM_prediction$overall[1], SVM_prediction$overall[1], 1 - DT_prediction$overall[1], 1 - RF_prediction$overall[1], 1 - GBM_prediction$overall[1], 1 - SVM_prediction$overall[1]), ncol = 2), digits = 4)
## Specify the column names and row names of matrix
colnames(result) = c('Accuracy', 'Out of Sample Error')
rownames(result) = c('Decision Trees', 'Random Forest', 'Gradient Boosted Trees', 'Support Vector Machine')
## Assign and display the table
final = as.table(result)
final
## Accuracy Out of Sample Error
## Decision Trees 0.5366 0.4634
## Random Forest 0.9958 0.0042
## Gradient Boosted Trees 0.9917 0.0083
## Support Vector Machine 0.7813 0.2187
Based on the results, Random Forest is the best model, with an accuracy rate of 0.9958 and an out of sample error of 0.0042.
We will now use the Random Forest model to predict the 20 cases on the test set.
predict <- predict(RF, testData)
print(predict)
## [1] B A B A A E D B A A B C B A E E A B B B
## Levels: A B C D E