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, we will use data from accelerometers on the belt, forearm, arm, and dumbell of 6 participants to predict the manner in which they did the exercise.
After executing code you might want to go make a sandwich
library(caret)
## Loading required package: lattice
## Loading required package: ggplot2
library(rpart)
library(rpart.plot)
library(randomForest)
## randomForest 4.6-12
## Type rfNews() to see new features/changes/bug fixes.
##
## Attaching package: 'randomForest'
## The following object is masked from 'package:ggplot2':
##
## margin
library(corrplot)
We will assume that the data already sits in the same wd as our data. We will put these csv’s into data frames
trainRaw <- read.csv("C:/data/pml-training.csv")
testRaw <- read.csv("C:/data/pml-testing.csv")
dim(trainRaw)
## [1] 19622 160
dim(testRaw)
## [1] 20 160
The training data set contains 19622 observations and 160 variables, while the testing data set contains 20 observations and 160 variables. The “classe” variable in the training set is the outcome to predict.
As always, get rid of missing values and any variables that are not of interest.
sum(complete.cases(trainRaw))
Get rid of NA values.
trainRaw <- trainRaw[, colSums(is.na(trainRaw)) == 0]
testRaw <- testRaw[, colSums(is.na(testRaw)) == 0]
We do not need these timestamp variables, we need to trim our dataset so we only have meaningful information.
classe <- trainRaw$classe
trainRemove <- grepl("^X|timestamp|window", names(trainRaw))
trainRaw <- trainRaw[, !trainRemove]
trainCleaned <- trainRaw[, sapply(trainRaw, is.numeric)]
trainCleaned$classe <- classe
testRemove <- grepl("^X|timestamp|window", names(testRaw))
testRaw <- testRaw[, !testRemove]
testCleaned <- testRaw[, sapply(testRaw, is.numeric)]
The training and test data set now have the same number of columns.. The “classe” variable is still in the cleaned training set.
We will do a 70/30 split of the scrubbed training set and will use the validation data set to conduct cross validation in future steps.
set.seed(22519) # For reproducibile purpose
inTrain <- createDataPartition(trainCleaned$classe, p=0.70, list=F)
trainData <- trainCleaned[inTrain, ]
testData <- trainCleaned[-inTrain, ]
Random Forest is our predictive tool of choice because it automatically selects important variables and is resistant to covariates and outliers(which will exist in most data sets). We will use 5-fold cross validation when applying the algorithm.
controlRf <- trainControl(method="cv", 5)
modelRf <- train(classe ~ ., data=trainData, method="rf", trControl=controlRf, ntree=250)
modelRf
## Random Forest
##
## 13737 samples
## 52 predictor
## 5 classes: 'A', 'B', 'C', 'D', 'E'
##
## No pre-processing
## Resampling: Cross-Validated (5 fold)
## Summary of sample sizes: 10989, 10989, 10990, 10990, 10990
## Resampling results across tuning parameters:
##
## mtry Accuracy Kappa Accuracy SD Kappa SD
## 2 0.9903909 0.9878440 0.001223542 0.001547356
## 27 0.9911190 0.9887654 0.001326827 0.001679000
## 52 0.9844213 0.9802917 0.002838009 0.003590429
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 27.
Then we hit the validation dataset with the model:
predictRf <- predict(modelRf, testData)
confusionMatrix(testData$classe, predictRf)
## Confusion Matrix and Statistics
##
## Reference
## Prediction A B C D E
## A 1673 0 0 0 1
## B 6 1129 4 0 0
## C 0 0 1021 5 0
## D 0 0 15 947 2
## E 0 0 1 6 1075
##
## Overall Statistics
##
## Accuracy : 0.9932
## 95% CI : (0.9908, 0.9951)
## No Information Rate : 0.2853
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9914
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: A Class: B Class: C Class: D Class: E
## Sensitivity 0.9964 1.0000 0.9808 0.9885 0.9972
## Specificity 0.9998 0.9979 0.9990 0.9965 0.9985
## Pos Pred Value 0.9994 0.9912 0.9951 0.9824 0.9935
## Neg Pred Value 0.9986 1.0000 0.9959 0.9978 0.9994
## Prevalence 0.2853 0.1918 0.1769 0.1628 0.1832
## Detection Rate 0.2843 0.1918 0.1735 0.1609 0.1827
## Detection Prevalence 0.2845 0.1935 0.1743 0.1638 0.1839
## Balanced Accuracy 0.9981 0.9989 0.9899 0.9925 0.9979
accuracy <- postResample(predictRf, testData$classe)
accuracy
## Accuracy Kappa
## 0.9932031 0.9914021
oose <- 1 - as.numeric(confusionMatrix(testData$classe, predictRf)$overall[1])
oose
## [1] 0.006796941
Accuracy: ~99% Estimated Out-of-Sample Error: ~0.5% ## Predicting for Test Data Set Now, we apply the model to the original testing data set downloaded from the data source. We remove the problem_id column first.
result <- predict(modelRf, testCleaned[, -length(names(testCleaned))])
result
## [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
corrPlot <- cor(trainData[, -length(names(trainData))])
corrplot(corrPlot, method="color")
2. Decision Tree Visualization
treeModel <- rpart(classe ~ ., data=trainData, method="class")
prp(treeModel) # fast plot