Introduction

This project aims to predict the correctness of weightlifting exercises using data collected from accelerometers on belts, forearms, arms, and dumbbells.

Load Libraries

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.5     ✓ purrr   0.3.4
## ✓ tibble  3.0.1     ✓ dplyr   1.0.0
## ✓ tidyr   1.1.0     ✓ stringr 1.4.0
## ✓ readr   1.3.1     ✓ forcats 0.5.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(caret)
## Loading required package: lattice
## 
## Attaching package: 'caret'
## The following object is masked from 'package:purrr':
## 
##     lift
library(randomForest)
## randomForest 4.6-14
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## The following object is masked from 'package:dplyr':
## 
##     combine
## The following object is masked from 'package:ggplot2':
## 
##     margin
library(knitr)

Load Data

train_url <- "https://d396qusza40orc.cloudfront.net/predmachlearn/pml-training.csv"
test_url <- "https://d396qusza40orc.cloudfront.net/predmachlearn/pml-testing.csv"

train_data <- read.csv(url(train_url), na.strings = c("", "NA", "#DIV/0!"))
test_data <- read.csv(url(test_url), na.strings = c("", "NA", "#DIV/0!"))

Data Cleaning

# Remove columns with too many missing values
train_data <- train_data[, colSums(is.na(train_data)) < nrow(train_data) * 0.5]
test_data <- test_data[, colSums(is.na(test_data)) < nrow(test_data) * 0.5]

# Remove non-predictive columns
non_predictive <- c("X", "user_name", "raw_timestamp_part_1", "raw_timestamp_part_2", 
                    "cvtd_timestamp", "new_window", "num_window")

train_data <- train_data %>% select(-all_of(non_predictive))
test_data <- test_data %>% select(-all_of(non_predictive))

# Convert 'classe' to factor
train_data$classe <- as.factor(train_data$classe)

# Ensure all predictors (except target variable) are numeric
train_data <- train_data %>% mutate(across(where(is.character), as.numeric))
test_data <- test_data %>% mutate(across(where(is.character), as.numeric))

Train-Test Split

set.seed(123)
trainIndex <- createDataPartition(train_data$classe, p = 0.7, list = FALSE)
train_set <- train_data[trainIndex, ]
test_set <- train_data[-trainIndex, ]

Train Model

set.seed(123)
model_rf <- randomForest(classe ~ ., data = train_set, ntree = 100, importance = TRUE)
print(model_rf)
## 
## Call:
##  randomForest(formula = classe ~ ., data = train_set, ntree = 100,      importance = TRUE) 
##                Type of random forest: classification
##                      Number of trees: 100
## No. of variables tried at each split: 7
## 
##         OOB estimate of  error rate: 0.62%
## Confusion matrix:
##      A    B    C    D    E class.error
## A 3902    4    0    0    0 0.001024066
## B   13 2636    9    0    0 0.008276900
## C    0   16 2373    7    0 0.009599332
## D    0    0   28 2223    1 0.012877442
## E    0    0    2    5 2518 0.002772277

Model Evaluation

predictions <- predict(model_rf, test_set)
test_set$classe <- as.factor(test_set$classe)  # Ensure classe is a factor

conf_matrix <- confusionMatrix(predictions, test_set$classe)
print(conf_matrix)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    A    B    C    D    E
##          A 1674    5    0    0    0
##          B    0 1130    2    0    0
##          C    0    4 1024    8    4
##          D    0    0    0  956    4
##          E    0    0    0    0 1074
## 
## Overall Statistics
##                                          
##                Accuracy : 0.9954         
##                  95% CI : (0.9933, 0.997)
##     No Information Rate : 0.2845         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.9942         
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: A Class: B Class: C Class: D Class: E
## Sensitivity            1.0000   0.9921   0.9981   0.9917   0.9926
## Specificity            0.9988   0.9996   0.9967   0.9992   1.0000
## Pos Pred Value         0.9970   0.9982   0.9846   0.9958   1.0000
## Neg Pred Value         1.0000   0.9981   0.9996   0.9984   0.9983
## Prevalence             0.2845   0.1935   0.1743   0.1638   0.1839
## Detection Rate         0.2845   0.1920   0.1740   0.1624   0.1825
## Detection Prevalence   0.2853   0.1924   0.1767   0.1631   0.1825
## Balanced Accuracy      0.9994   0.9958   0.9974   0.9954   0.9963

Predictions on Testing Data

test_predictions <- predict(model_rf, test_data)
print(test_predictions)
##  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 
##  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