Summary

Firstly, the data and the necessary R packages were loaded. Then, we try to understand the nature of the data. We find out that most of the variables are numeric variables, and some variables have a lot of NA values. So, we filter the data by removing variables that have a lot of NA values or have a low variation.
Then, we partition our training data set into training set and validation set. Next, we begin training our model using random forest as our predictive algorithm on the training set. We validate our out-of-sample error rate by applying the model to predict the validation set. Low out-of-sample error rate was achieved on the validation set. Finally, we use our model to predict the test set and was able to achieve a 100% prediction accuracy.

Loading the Data and R Packages

setwd("C:/Users/User/Desktop")
training <- read.csv("pml-training.csv", na.strings = c("NA","#DIV/0!",""))
testing <- read.csv("pml-testing.csv", na.strings = c("NA","#DIV/0!",""))

library(plyr);library(dplyr);library(ggplot2); library(caret)

Understanding the Data

nc <- ncol(training)
str(training[,1:90])
'data.frame':   19622 obs. of  90 variables:
 $ X                      : int  1 2 3 4 5 6 7 8 9 10 ...
 $ user_name              : Factor w/ 6 levels "adelmo","carlitos",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ raw_timestamp_part_1   : int  1323084231 1323084231 1323084231 1323084232 1323084232 1323084232 1323084232 1323084232 1323084232 1323084232 ...
 $ raw_timestamp_part_2   : int  788290 808298 820366 120339 196328 304277 368296 440390 484323 484434 ...
 $ cvtd_timestamp         : Factor w/ 20 levels "02/12/2011 13:32",..: 9 9 9 9 9 9 9 9 9 9 ...
 $ new_window             : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
 $ num_window             : int  11 11 11 12 12 12 12 12 12 12 ...
 $ roll_belt              : num  1.41 1.41 1.42 1.48 1.48 1.45 1.42 1.42 1.43 1.45 ...
 $ pitch_belt             : num  8.07 8.07 8.07 8.05 8.07 8.06 8.09 8.13 8.16 8.17 ...
 $ yaw_belt               : num  -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 ...
 $ total_accel_belt       : int  3 3 3 3 3 3 3 3 3 3 ...
 $ kurtosis_roll_belt     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_picth_belt    : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_yaw_belt      : logi  NA NA NA NA NA NA ...
 $ skewness_roll_belt     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_roll_belt.1   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_yaw_belt      : logi  NA NA NA NA NA NA ...
 $ max_roll_belt          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_picth_belt         : int  NA NA NA NA NA NA NA NA NA NA ...
 $ max_yaw_belt           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_roll_belt          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_pitch_belt         : int  NA NA NA NA NA NA NA NA NA NA ...
 $ min_yaw_belt           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_roll_belt    : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_pitch_belt   : int  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_yaw_belt     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_total_accel_belt   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_roll_belt          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_roll_belt       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_roll_belt          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_pitch_belt         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_pitch_belt      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_pitch_belt         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_yaw_belt           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_yaw_belt        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_yaw_belt           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ gyros_belt_x           : num  0 0.02 0 0.02 0.02 0.02 0.02 0.02 0.02 0.03 ...
 $ gyros_belt_y           : num  0 0 0 0 0.02 0 0 0 0 0 ...
 $ gyros_belt_z           : num  -0.02 -0.02 -0.02 -0.03 -0.02 -0.02 -0.02 -0.02 -0.02 0 ...
 $ accel_belt_x           : int  -21 -22 -20 -22 -21 -21 -22 -22 -20 -21 ...
 $ accel_belt_y           : int  4 4 5 3 2 4 3 4 2 4 ...
 $ accel_belt_z           : int  22 22 23 21 24 21 21 21 24 22 ...
 $ magnet_belt_x          : int  -3 -7 -2 -6 -6 0 -4 -2 1 -3 ...
 $ magnet_belt_y          : int  599 608 600 604 600 603 599 603 602 609 ...
 $ magnet_belt_z          : int  -313 -311 -305 -310 -302 -312 -311 -313 -312 -308 ...
 $ roll_arm               : num  -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 ...
 $ pitch_arm              : num  22.5 22.5 22.5 22.1 22.1 22 21.9 21.8 21.7 21.6 ...
 $ yaw_arm                : num  -161 -161 -161 -161 -161 -161 -161 -161 -161 -161 ...
 $ total_accel_arm        : int  34 34 34 34 34 34 34 34 34 34 ...
 $ var_accel_arm          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_roll_arm           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_roll_arm        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_roll_arm           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_pitch_arm          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_pitch_arm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_pitch_arm          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_yaw_arm            : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_yaw_arm         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_yaw_arm            : num  NA NA NA NA NA NA NA NA NA NA ...
 $ gyros_arm_x            : num  0 0.02 0.02 0.02 0 0.02 0 0.02 0.02 0.02 ...
 $ gyros_arm_y            : num  0 -0.02 -0.02 -0.03 -0.03 -0.03 -0.03 -0.02 -0.03 -0.03 ...
 $ gyros_arm_z            : num  -0.02 -0.02 -0.02 0.02 0 0 0 0 -0.02 -0.02 ...
 $ accel_arm_x            : int  -288 -290 -289 -289 -289 -289 -289 -289 -288 -288 ...
 $ accel_arm_y            : int  109 110 110 111 111 111 111 111 109 110 ...
 $ accel_arm_z            : int  -123 -125 -126 -123 -123 -122 -125 -124 -122 -124 ...
 $ magnet_arm_x           : int  -368 -369 -368 -372 -374 -369 -373 -372 -369 -376 ...
 $ magnet_arm_y           : int  337 337 344 344 337 342 336 338 341 334 ...
 $ magnet_arm_z           : int  516 513 513 512 506 513 509 510 518 516 ...
 $ kurtosis_roll_arm      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_picth_arm     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_yaw_arm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_roll_arm      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_pitch_arm     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_yaw_arm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_roll_arm           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_picth_arm          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_yaw_arm            : int  NA NA NA NA NA NA NA NA NA NA ...
 $ min_roll_arm           : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_pitch_arm          : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_yaw_arm            : int  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_roll_arm     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_pitch_arm    : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_yaw_arm      : int  NA NA NA NA NA NA NA NA NA NA ...
 $ roll_dumbbell          : num  13.1 13.1 12.9 13.4 13.4 ...
 $ pitch_dumbbell         : num  -70.5 -70.6 -70.3 -70.4 -70.4 ...
 $ yaw_dumbbell           : num  -84.9 -84.7 -85.1 -84.9 -84.9 ...
 $ kurtosis_roll_dumbbell : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_picth_dumbbell: num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_yaw_dumbbell  : logi  NA NA NA NA NA NA ...
 $ skewness_roll_dumbbell : num  NA NA NA NA NA NA NA NA NA NA ...
str(training[,91:nc])
'data.frame':   19622 obs. of  70 variables:
 $ skewness_pitch_dumbbell : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_yaw_dumbbell   : logi  NA NA NA NA NA NA ...
 $ max_roll_dumbbell       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_picth_dumbbell      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_yaw_dumbbell        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_roll_dumbbell       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_pitch_dumbbell      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_yaw_dumbbell        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_roll_dumbbell : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_pitch_dumbbell: num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_yaw_dumbbell  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ total_accel_dumbbell    : int  37 37 37 37 37 37 37 37 37 37 ...
 $ var_accel_dumbbell      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_roll_dumbbell       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_roll_dumbbell    : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_roll_dumbbell       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_pitch_dumbbell      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_pitch_dumbbell   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_pitch_dumbbell      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_yaw_dumbbell        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_yaw_dumbbell     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_yaw_dumbbell        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ gyros_dumbbell_x        : num  0 0 0 0 0 0 0 0 0 0 ...
 $ gyros_dumbbell_y        : num  -0.02 -0.02 -0.02 -0.02 -0.02 -0.02 -0.02 -0.02 -0.02 -0.02 ...
 $ gyros_dumbbell_z        : num  0 0 0 -0.02 0 0 0 0 0 0 ...
 $ accel_dumbbell_x        : int  -234 -233 -232 -232 -233 -234 -232 -234 -232 -235 ...
 $ accel_dumbbell_y        : int  47 47 46 48 48 48 47 46 47 48 ...
 $ accel_dumbbell_z        : int  -271 -269 -270 -269 -270 -269 -270 -272 -269 -270 ...
 $ magnet_dumbbell_x       : int  -559 -555 -561 -552 -554 -558 -551 -555 -549 -558 ...
 $ magnet_dumbbell_y       : int  293 296 298 303 292 294 295 300 292 291 ...
 $ magnet_dumbbell_z       : num  -65 -64 -63 -60 -68 -66 -70 -74 -65 -69 ...
 $ roll_forearm            : num  28.4 28.3 28.3 28.1 28 27.9 27.9 27.8 27.7 27.7 ...
 $ pitch_forearm           : num  -63.9 -63.9 -63.9 -63.9 -63.9 -63.9 -63.9 -63.8 -63.8 -63.8 ...
 $ yaw_forearm             : num  -153 -153 -152 -152 -152 -152 -152 -152 -152 -152 ...
 $ kurtosis_roll_forearm   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_picth_forearm  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ kurtosis_yaw_forearm    : logi  NA NA NA NA NA NA ...
 $ skewness_roll_forearm   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_pitch_forearm  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ skewness_yaw_forearm    : logi  NA NA NA NA NA NA ...
 $ max_roll_forearm        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_picth_forearm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ max_yaw_forearm         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_roll_forearm        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_pitch_forearm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ min_yaw_forearm         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_roll_forearm  : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_pitch_forearm : num  NA NA NA NA NA NA NA NA NA NA ...
 $ amplitude_yaw_forearm   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ total_accel_forearm     : int  36 36 36 36 36 36 36 36 36 36 ...
 $ var_accel_forearm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_roll_forearm        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_roll_forearm     : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_roll_forearm        : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_pitch_forearm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_pitch_forearm    : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_pitch_forearm       : num  NA NA NA NA NA NA NA NA NA NA ...
 $ avg_yaw_forearm         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ stddev_yaw_forearm      : num  NA NA NA NA NA NA NA NA NA NA ...
 $ var_yaw_forearm         : num  NA NA NA NA NA NA NA NA NA NA ...
 $ gyros_forearm_x         : num  0.03 0.02 0.03 0.02 0.02 0.02 0.02 0.02 0.03 0.02 ...
 $ gyros_forearm_y         : num  0 0 -0.02 -0.02 0 -0.02 0 -0.02 0 0 ...
 $ gyros_forearm_z         : num  -0.02 -0.02 0 0 -0.02 -0.03 -0.02 0 -0.02 -0.02 ...
 $ accel_forearm_x         : int  192 192 196 189 189 193 195 193 193 190 ...
 $ accel_forearm_y         : int  203 203 204 206 206 203 205 205 204 205 ...
 $ accel_forearm_z         : int  -215 -216 -213 -214 -214 -215 -215 -213 -214 -215 ...
 $ magnet_forearm_x        : int  -17 -18 -18 -16 -17 -9 -18 -9 -16 -22 ...
 $ magnet_forearm_y        : num  654 661 658 658 655 660 659 660 653 656 ...
 $ magnet_forearm_z        : num  476 473 469 469 473 478 470 474 476 473 ...
 $ classe                  : Factor w/ 5 levels "A","B","C","D",..: 1 1 1 1 1 1 1 1 1 1 ...

There are 159 predictors and 19622 observations. We observe that most predictors are numeric variables.

Cleaning the Data

We can perform some simple variable selection by removing columns that have more than 1% of NA values or absolute value of coefficient of variation of less than 50% (removing variables that have low variation). Besides, the first 5 variables are not meaningful in predicting the outcome, i.e. “X”, “user_name” and the 3 “timestamp” variables.

cleandf <- function(df){
      df <- df[,-c(1:5)] #remove X, user_name, and timestamp
      cname <- colnames(df) 
      
      sub_cname_log <- sapply(cname, FUN = function(x){
            if(x %in% "classe"){
                  return(T)     
            }else{
                  df[,x] <<- as.numeric(df[,x])
                  v <- df[,x]
                  tf <- sum(is.na(v))/nrow(df) < 0.01 & abs(sd(v)/mean(v)) > 0.5
                  return(tf)
            }
      })
      return(df[sub_cname_log])
}

cdf.train1 <- cleandf(training); #clean the training data
df1 <- cdf.train1  #creating backup

nc2 <- ncol(cdf.train1)
nc2 
## [1] 50

The resulting data frame have 49 predictors left. Now we can train our model.

Training the Model using Random Forest

Data Partitioning

First, we partition our training data into the training set and validation set, which comprises of 60% and 40% of the original training data respectively.
The training set will be used to train the model; the validation set will be used to validate the out-of-sample error rate of the model.

set.seed(123)
intrain <- createDataPartition(y = df1$classe, p = 0.6, list = F) #60% training, 40% validation set
trn0 <- df1[intrain,]; val0 <- df1[-intrain,]

Training the Model

Random forest is used to train the model, in favour of its prediction accuracy.

model <- "fit1.RData"
if (!file.exists(model)) { #To cache the training process
      
      system.time({
                  fit1 <- train(classe ~ ., method = "rf", data = trn0) #training the model
      })
      save(fit1, file = "fit1.RData")

} else {
      # Good model exists from previous run, load it and use it.  
      load(file = "fit1.RData", verbose = TRUE)
}
## Loading objects:
##   fit1

Predicting on the Validation Set using the Fitted Model

pred1 <- predict(fit1, val0)
acc1 <- confusionMatrix(val0$classe, pred1)$overall[1] #Prediction accuracy

confusionMatrix(val0$classe, pred1)
Confusion Matrix and Statistics

          Reference
Prediction    A    B    C    D    E
         A 2232    0    0    0    0
         B    1 1515    2    0    0
         C    0    4 1361    3    0
         D    0    0    8 1278    0
         E    0    0    0    1 1441

Overall Statistics
                                          
               Accuracy : 0.9976          
                 95% CI : (0.9962, 0.9985)
    No Information Rate : 0.2846          
    P-Value [Acc > NIR] : < 2.2e-16       
                                          
                  Kappa : 0.9969          
 Mcnemar's Test P-Value : NA              

Statistics by Class:

                     Class: A Class: B Class: C Class: D Class: E
Sensitivity            0.9996   0.9974   0.9927   0.9969   1.0000
Specificity            1.0000   0.9995   0.9989   0.9988   0.9998
Pos Pred Value         1.0000   0.9980   0.9949   0.9938   0.9993
Neg Pred Value         0.9998   0.9994   0.9985   0.9994   1.0000
Prevalence             0.2846   0.1936   0.1747   0.1634   0.1837
Detection Rate         0.2845   0.1931   0.1735   0.1629   0.1837
Detection Prevalence   0.2845   0.1935   0.1744   0.1639   0.1838
Balanced Accuracy      0.9998   0.9984   0.9958   0.9978   0.9999

The prediction accuracy on the validation set is 0.9975784, hence the out-of-sample error rate is 0.0024216, which is very satisfactory. No adjustment is needed, we can proceed to predict the test set.

Predicting on the Test Set using the Fitted Model

Finally, we apply our model to predict the 20 test cases.

pred2 <- predict(fit1, newdata = testing)
print(data.frame(pred2))
   pred2
1      B
2      A
3      B
4      A
5      A
6      E
7      D
8      B
9      A
10     A
11     B
12     C
13     B
14     A
15     E
16     E
17     A
18     B
19     B
20     B

The printed predictions are then used to verify against the “Course Project Prediction Quiz”. 100% accuracy was obtained!