-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathassignment.Rmd
More file actions
171 lines (132 loc) · 7.61 KB
/
Copy pathassignment.Rmd
File metadata and controls
171 lines (132 loc) · 7.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
---
title: "Predicting the correct way to exercice"
author: "Anna-Lea Lesage"
date: "October 23, 2019"
output:
html_document:
keep_md: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## Summary
Is it possible to infer from the way a person is doing an exercice whether they are doing it right?
To answer this question, I used the existing weight lifting dataset. After selecting specific columns as predictors, I fitted a boosted tree model to the class variable. The in-sample error was very small, less than 5%, suggesting a possible over-fitting of the model. To verify this assumption, I checked whether some columns were correlated to others, and removed those which presented a high correlation rate ( greater than 80%). Still the new model performed very well and had an out-of sample error of about 6%. The last model was used to predict on hand of the given test set the class of the exercise.
## Data acquisition and cleaning
In order to properly determine whether an exercice is done correctly, 6 participants were asked to perform simple weight lifting exercices. They were asked to perform the exercice correctly on one set, and wrongly on four other sets. Each participant was fitted with 3 sensors (forearm, arm and belt), and a last sensor was located on the dumbbell. All the measurements have been compiled together into one table.
The data has been downloaded and saved in the working directory. It is already split into a training and a test set. We set the test set aside for the moment. It'll be used in the last section for the prediction.
The training data consists of about 20000 observations of 160 variables.
```{r}
data <- read.csv("pml-training.csv", as.is=TRUE, na.strings=c("", " ", NA))
dim(data)
```
The variable *classe* is our outcome. It defines whether the exercice has been performed correstly, class A, or incorrectly, classes B to E.
### Data Preparation
We separate the data into a training and a test set. The provided test set will serve as validation set to verify the out-of-sample errors.
```{r warning=FALSE, results=FALSE, message=FALSE}
library(caret)
inTrain <- createDataPartition(data$classe, p=0.7, list=FALSE)
training <- data[inTrain, ]
testing <- data[-inTrain, ]
```
Using the `str` function of R, we can have a quick look at the data. It seems that many columns do not have any entries of very few of them. We further investigate this using the following function:
```{r}
nonzero.fraction <- function(X) {
nonzero.counts <- length(which(X != 0))
nonzero.counts / length(X)
}
nonzero.columns <- lapply(training, nonzero.fraction)
non.zero.columns <- sapply(nonzero.columns, function(X) {X > 0.8}, simplify=TRUE)
```
I decided to keep all the columns which have more than 80% of non-zero values. The rest will not be used in the model building since the data is too sparse. This step reduces the number of potential variables to 59.
```{r}
training <- training[, non.zero.columns]
dim(training)
```
### Column selection
The number of predictors is still very high. Some of the columns could be discarded from the model:
* The user name, is not relevant for the prediction since we want to be able to predict the correctness of the mouvement for any user
* The raw_timestamp_part_1, is the duplicate of the cvtd_timestamp. We can safely discard one (or both)
* the new_window and num_window columns,
* the X column, as it represents the number of rows.
```{r message=FALSE, warning=FALSE}
discarded.columns <- c("X", "user_name", "raw_timestamp_part_1",
"raw_timestamp_part_2", "new_window", "num_window",
"cvtd_timestamp")
library(dplyr)
training <- training %>% select(-discarded.columns)
training$classe <- as.factor(training$classe)
```
## Model Selection
I normalize the data in the pre-processing step.
For the model I have chosen a boosted tree model as it allows both regression and classification.
Cross-validation is performed within the train function. I've set it to use a K-fold method using 10 folds (which means that each test fold has nearly a 1300 data points).
Furthermore, to improve the speed of the calculation, I'll allow parallel processing within the caret package. For this I use the packages *parallel* and *doParallel*.
```{r}
cluster <- parallel::makeCluster(parallel::detectCores() - 1)
doParallel::registerDoParallel()
```
```{r cache=TRUE}
cross.validation.params <- trainControl(## 10-fold
method="cv",
number=10,
allowParallel = TRUE ## To use the multiprocessing cluster created ealier.
)
model <- train(classe ~ ., data=training, method="gbm",
preProcess=c("center", "scale"),
trControl=cross.validation.params,
verbose=FALSE
)
parallel::stopCluster(cluster)
```
## Accuracy of the training set
With the cross-validation, we can already have a decent idea of the in-sample error. Using the *gbm* model gives also the possibility to visualize the accuracy of the model for different settings. Here I kept to the default settings for the interaction depth, number of tree and a shrinkage of 10%.
```{r}
plot(model)
```
We see that we have a very good accuracy (over 95%) using only the training set. The best configuration is reached with 150 nodes in the tree and an interaction depth of 3.
```{r}
model.pred.train <- confusionMatrix.train(model)
model.pred.train
```
### Verification of the out-sample error using the created test set.
The model performs really well on the training set. However, how does it perform on the test set we created in step 1.
```{r}
pred.test <- predict(model, newdata=testing)
conf.pred.test <- confusionMatrix(as.factor(testing$class), pred.test)
conf.pred.test$overall
```
As expected, the accuracy is slightly less than on the training dataset but remains still above the 95%.
## Improvement of the model
Since we have already a pretty low in-sample error (less than 5%), we can ask ourself whether we are not overfitting the data. Have we selected the right predictors? Maybe some predictors are correlated to each other and will increase the bias of the model.
Let's look which columns are correlated and remove those from the predictors.
```{r}
corrs <- cor(training[, -ncol(training)]) ## I remove the last column classe as it is a factor
highCorr <- findCorrelation(corrs, 0.8) ## Find correlations above 0.8
## Those are the index of the correlated columns -> we'll remove those
training <- training[, -highCorr]
```
Let's calculate the model again and see if how it performs compared to the first one.
```{r cache=TRUE}
cluster <- parallel::makeCluster(parallel::detectCores() - 1)
doParallel::registerDoParallel()
improved.model <- train(classe ~ ., data = training, method="gbm",
preProcess=c("center", "scale"),
trControl=cross.validation.params,
verbose=FALSE
)
parallel::stopCluster(cluster)
```
```{r}
impr.pred.test <- predict(improved.model, newdata=testing)
impr.conf.pred.test <- confusionMatrix(as.factor(testing$class), impr.pred.test)
impr.conf.pred.test$overall
```
The out-of sample error has increased a bit compared to the previous model made by using all the predictors regardless of their correlation. Indeed the accuracy of the first model was at over `r conf.pred.test$overall * 100`%, now we have an accuracy of `r impr.conf.pred.test$overall * 100`%
## Prediction on the validation set
The validation set consists of 20 rows of data where we don't know the class the exercice. Let's see how our model predicts each case:
```{r}
validation <- read.csv("pml-testing.csv")
val.pred <- predict(improved.model, newdata=validation)
val.pred
```