1. Introdução

Este projeto utiliza dados de acelerômetros de 6 participantes realizando exercícios com halteres. O objetivo é prever a classe do exercício (A, B, C, D, E) – que representa a qualidade do movimento – com base em variáveis de sensores.

Os dados foram obtidos da fonte: http://groupware.les.inf.puc-rio.br/har.

2. Carregamento e Limpeza dos Dados

2.1 Download dos dados

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

# Carregar dados
train_raw <- read.csv(train_url, na.strings = c("NA", "#DIV/0!", ""))
test_raw  <- read.csv(test_url,  na.strings = c("NA", "#DIV/0!", ""))

2.2 Limpeza de dados

# Remover colunas com mais de 90% de valores NA
na_threshold <- 0.9

# IMPORTANTE: a seleção de colunas é feita SOMENTE com base no conjunto de
# treino, e depois aplicada ao teste. Fazer essa seleção separadamente em
# train_raw e test_raw pode gerar conjuntos de colunas diferentes entre os
# dois, o que quebra (ou distorce) a previsão final do modelo.
cols_to_keep <- names(train_raw)[colMeans(is.na(train_raw)) < na_threshold]

train_clean <- train_raw[, cols_to_keep]

# "classe" não existe no conjunto de teste (é a variável a ser prevista)
cols_to_keep_test <- setdiff(cols_to_keep, "classe")
test_clean <- test_raw[, cols_to_keep_test]

# Remover colunas irrelevantes
col_irrelevantes <- c(
  "X",
  "user_name",
  "raw_timestamp_part_1",
  "raw_timestamp_part_2",
  "cvtd_timestamp",
  "new_window",
  "num_window"
)

train_clean <- train_clean[, !(names(train_clean) %in% col_irrelevantes)]

test_clean <- test_clean[, !(names(test_clean) %in% col_irrelevantes)]

# Remover problem_id do conjunto de teste
test_clean <- test_clean[, names(test_clean) != "problem_id"]

# Transformar a variável resposta em fator
train_clean$classe <- as.factor(train_clean$classe)

# Conferir as classes
print(levels(train_clean$classe))
## [1] "A" "B" "C" "D" "E"
print(table(train_clean$classe))
## 
##    A    B    C    D    E 
## 5580 3797 3422 3216 3607
# Verificar dimensões
print(dim(train_clean))
## [1] 19622    53
print(dim(test_clean))
## [1] 20 52

3. Análise Exploratória

# Estrutura dos dados
str(train_clean[, 1:10])
## 'data.frame':    19622 obs. of  10 variables:
##  $ 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 ...
##  $ 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 ...
# Resumo estatístico
summary(train_clean[, 1:10])
##    roll_belt        pitch_belt          yaw_belt       total_accel_belt
##  Min.   :-28.90   Min.   :-55.8000   Min.   :-180.00   Min.   : 0.00   
##  1st Qu.:  1.10   1st Qu.:  1.7600   1st Qu.: -88.30   1st Qu.: 3.00   
##  Median :113.00   Median :  5.2800   Median : -13.00   Median :17.00   
##  Mean   : 64.41   Mean   :  0.3053   Mean   : -11.21   Mean   :11.31   
##  3rd Qu.:123.00   3rd Qu.: 14.9000   3rd Qu.:  12.90   3rd Qu.:18.00   
##  Max.   :162.00   Max.   : 60.3000   Max.   : 179.00   Max.   :29.00   
##   gyros_belt_x        gyros_belt_y       gyros_belt_z      accel_belt_x     
##  Min.   :-1.040000   Min.   :-0.64000   Min.   :-1.4600   Min.   :-120.000  
##  1st Qu.:-0.030000   1st Qu.: 0.00000   1st Qu.:-0.2000   1st Qu.: -21.000  
##  Median : 0.030000   Median : 0.02000   Median :-0.1000   Median : -15.000  
##  Mean   :-0.005592   Mean   : 0.03959   Mean   :-0.1305   Mean   :  -5.595  
##  3rd Qu.: 0.110000   3rd Qu.: 0.11000   3rd Qu.:-0.0200   3rd Qu.:  -5.000  
##  Max.   : 2.220000   Max.   : 0.64000   Max.   : 1.6200   Max.   :  85.000  
##   accel_belt_y     accel_belt_z    
##  Min.   :-69.00   Min.   :-275.00  
##  1st Qu.:  3.00   1st Qu.:-162.00  
##  Median : 35.00   Median :-152.00  
##  Mean   : 30.15   Mean   : -72.59  
##  3rd Qu.: 61.00   3rd Qu.:  27.00  
##  Max.   :164.00   Max.   : 105.00
# Distribuição da variável resposta (classe)
ggplot(train_clean, aes(x = classe)) +
  geom_bar(fill = "steelblue") +
  labs(title = "Distribuição da Classe", x = "Classe", y = "Frequência")

# Correlação entre variáveis numéricas
num_vars <- train_clean[, sapply(train_clean, is.numeric)]
cor_matrix <- cor(num_vars, use = "pairwise.complete.obs")
corrplot(cor_matrix, method = "color", type = "upper", tl.cex = 0.4, number.cex = 0.5)

4. Pré-processamento e Divisão dos Dados

set.seed(123)

# Garantir que classe seja fator
train_clean$classe <- factor(train_clean$classe)

# Dividir em 70% treino e 30% validação
inTrain <- createDataPartition(
  train_clean$classe,
  p = 0.7,
  list = FALSE
)

training <- train_clean[inTrain, ]
validation <- train_clean[-inTrain, ]

# Verificar dimensões
print(dim(training))
## [1] 13737    53
print(dim(validation))
## [1] 5885   53
# Verificar distribuição das classes
print(table(training$classe))
## 
##    A    B    C    D    E 
## 3906 2658 2396 2252 2525
print(table(validation$classe))
## 
##    A    B    C    D    E 
## 1674 1139 1026  964 1082

5. Treinamento do Modelo

5.1 Modelo 1: Árvore de Decisão (baseline)

set.seed(123)
model_rpart <- rpart(classe ~ ., data = training, method = "class")
rpart.plot(model_rpart, main = "Árvore de Decisão")

5.2 Modelo 2: Random Forest (escolhido)

set.seed(123)
model_rf <- randomForest(classe ~ ., data = training, ntree = 150, importance = TRUE)

# Importância das variáveis
varImpPlot(model_rf, main = "Importância das Variáveis - Random Forest")

6. Avaliação do Modelo (Validação Cruzada e Erro Fora da Amostra)

# Previsão na validação
pred_rf <- predict(model_rf, validation)

# Matriz de confusão
confusionMatrix(pred_rf, validation$classe)
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction    A    B    C    D    E
##          A 1674    4    0    0    0
##          B    0 1131    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.9956          
##                  95% CI : (0.9935, 0.9971)
##     No Information Rate : 0.2845          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9944          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: A Class: B Class: C Class: D Class: E
## Sensitivity            1.0000   0.9930   0.9981   0.9917   0.9926
## Specificity            0.9991   0.9996   0.9967   0.9992   1.0000
## Pos Pred Value         0.9976   0.9982   0.9846   0.9958   1.0000
## Neg Pred Value         1.0000   0.9983   0.9996   0.9984   0.9983
## Prevalence             0.2845   0.1935   0.1743   0.1638   0.1839
## Detection Rate         0.2845   0.1922   0.1740   0.1624   0.1825
## Detection Prevalence   0.2851   0.1925   0.1767   0.1631   0.1825
## Balanced Accuracy      0.9995   0.9963   0.9974   0.9954   0.9963
# Erro fora da amostra (out-of-sample error)
oos_error <- mean(pred_rf != validation$classe)
cat("Erro fora da amostra estimado:", round(oos_error * 100, 2), "%")
## Erro fora da amostra estimado: 0.44 %
cat("Acurácia esperada:", round((1 - oos_error) * 100, 2), "%")
## Acurácia esperada: 99.56 %
# Erro dentro da amostra (in-sample)
insample_error <- mean(predict(model_rf, training) != training$classe)
cat("Erro dentro da amostra:", round(insample_error * 100, 2), "%")
## Erro dentro da amostra: 0 %

7. Previsão para os 20 Casos de Teste

# Previsão final nos dados de teste
previsoes <- predict(model_rf, test_clean)
previsoes
##  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

8. Conclusões

  • O modelo Random Forest apresentou excelente desempenho, com erro fora da amostra estimado em menos de 1%.
  • A validação cruzada (usando o conjunto de validação) confirma a robustez do modelo.
  • As variáveis mais importantes foram relacionadas ao acelerômetro do braço e haltere.
  • O modelo foi aplicado aos 20 casos de teste com alta confiança.

9. Apêndice: Respostas para o Questionário

# Gerar arquivo com as previsões para submissão
write.table(previsoes, file = "previsoes_quiz.txt", row.names = FALSE, col.names = FALSE)

Como submeter no questionário:

Copie os valores abaixo:

previsoes
##  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