This project aims to predict the correctness of weightlifting exercises using data collected from accelerometers on belts, forearms, arms, and dumbbells.
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)
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!"))
# 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))
set.seed(123)
trainIndex <- createDataPartition(train_data$classe, p = 0.7, list = FALSE)
train_set <- train_data[trainIndex, ]
test_set <- train_data[-trainIndex, ]
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
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
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