library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.3     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(caret)
## Loading required package: lattice
## 
## Attaching package: 'caret'
## 
## The following object is masked from 'package:purrr':
## 
##     lift
library(randomForest)
## randomForest 4.7-1.2
## 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
## 3. Carga de datos

data(iris)
head(iris)
## 4. Análisis exploratorio (EDA)

# Distribución de clases
ggplot(iris, aes(x = Species, fill = Species)) +
  geom_bar() +
  theme_minimal() +
  labs(title = "Distribución de especies")

# Boxplots 
iris %>%
  pivot_longer(cols = -Species) %>%
  ggplot(aes(x = Species, y = value, fill = Species)) +
  geom_boxplot() +
  facet_wrap(~name, scales = "free") +
  theme_minimal()

## 5. Train/Test (Entrenando al 70/30)
set.seed(123)

library(caret)

trainIndex <- createDataPartition(iris$Species, p = 0.7, list = FALSE)

train <- iris[trainIndex, ]
test  <- iris[-trainIndex, ]

# Ver tamaños
dim(train)
## [1] 105   5
dim(test)
## [1] 45  5
## 6. Entrenamiento del modelo
set.seed(123)

control <- trainControl(
  method = "cv",      # validación cruzada
  number = 5          # 5 folds
)

model_rf <- train(
  Species ~ .,
  data = train,
  method = "rf",
  trControl = control,
  tuneLength = 3
)

model_rf
## Random Forest 
## 
## 105 samples
##   4 predictor
##   3 classes: 'setosa', 'versicolor', 'virginica' 
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 84, 84, 84, 84, 84 
## Resampling results across tuning parameters:
## 
##   mtry  Accuracy   Kappa    
##   2     0.9428571  0.9142857
##   3     0.9428571  0.9142857
##   4     0.9428571  0.9142857
## 
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.
## 7.Predicciones

predictions <- predict(model_rf, newdata = test)
predictions
##  [1] setosa     setosa     setosa     setosa     setosa     setosa    
##  [7] setosa     setosa     setosa     setosa     setosa     setosa    
## [13] setosa     setosa     setosa     versicolor versicolor versicolor
## [19] versicolor versicolor versicolor virginica  versicolor versicolor
## [25] versicolor versicolor versicolor versicolor versicolor versicolor
## [31] virginica  virginica  virginica  virginica  virginica  virginica 
## [37] versicolor virginica  virginica  virginica  versicolor virginica 
## [43] virginica  virginica  virginica 
## Levels: setosa versicolor virginica
## 8.Evaluaciones

conf_matrix <- confusionMatrix(predictions, test$Species)
conf_matrix
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         15          0         0
##   versicolor      0         14         2
##   virginica       0          1        13
## 
## Overall Statistics
##                                          
##                Accuracy : 0.9333         
##                  95% CI : (0.8173, 0.986)
##     No Information Rate : 0.3333         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.9            
##                                          
##  Mcnemar's Test P-Value : NA             
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9333           0.8667
## Specificity                 1.0000            0.9333           0.9667
## Pos Pred Value              1.0000            0.8750           0.9286
## Neg Pred Value              1.0000            0.9655           0.9355
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3111           0.2889
## Detection Prevalence        0.3333            0.3556           0.3111
## Balanced Accuracy           1.0000            0.9333           0.9167
## Accuracy = 0.9333 (93.33%) De 45 observaciones, solo fallaste en 3, esto indica que es un modelo muy sólido.

## Kappa = 0.9, sabemos que si 0.8 → excelente acuerdo, nuestro modelo → muy por encima del azar, esto indica que el modelo no solo tiene buena accuracy, también presenta alta concordancia ajustada por azar (Kappa = 0.9).

## Análisis por clase

##Setosa
##Sensitivity = 1.0
##Specificity = 1.0
## Setosa es completamente separable del resto

##Versicolor
##Sensitivity = 0.93
##Precision (Pos Pred Value) = 0.87
## Conclusiones

## El modelo Random Forest logró una accuracy de 93.33%, mostrando un desempeño sólido en la clasificación. La clase setosa fue perfectamente identificada, lo que indica una clara separabilidad en los datos. Sin embargo, se observan errores entre las clases versicolor y virginica, lo cual sugiere una superposición en sus características, especialmente en variables relacionadas con los pétalos. El modelo presenta un Kappa de 0.9, lo que indica un alto nivel de concordancia más allá del azar.
var_imp <- varImp(model_rf)
var_imp
## rf variable importance
## 
##              Overall
## Petal.Width   100.00
## Petal.Length   89.51
## Sepal.Length   19.03
## Sepal.Width     0.00
plot(var_imp)

## Importancia de variables

##Las variables más relevantes para el modelo fueron Petal.Length y Petal.Width. Esto indica que las características relacionadas con los pétalos tienen mayor capacidad de discriminación entre especies, en comparación con las variables del sépalo.
## Guardamos el modelo
saveRDS(model_rf, "modelo_random_forest.rds")