#install.packages("ISLR")
#install.packages("tree")
#install.packages("randomForest")
#install.packages("corrplot")
library(ISLR)        
library(tree)         
library(dplyr)        
library(ggplot2)     
library(randomForest) 
library(corrplot) 
cat("Número de valores NA en Salary (antes):", sum(is.na(Hitters$Salary)), "\n")
## Número de valores NA en Salary (antes): 59
Hitters_clean <- Hitters %>%
  na.omit() %>%              
  select(-Years, -Hits)      

cat("Número de NAs en Salary (después):", sum(is.na(Hitters_clean$Salary)), "\n")
## Número de NAs en Salary (después): 0
cat("Dimensiones de la base de datos limpia:", dim(Hitters_clean)[1], "filas y", dim(Hitters_clean)[2], "columnas.\n")
## Dimensiones de la base de datos limpia: 263 filas y 18 columnas.
# Histograma de la variable Salary original
ggplot(Hitters_clean, aes(x = Salary)) +
  geom_histogram(bins = 20, fill = "skyblue", color = "black") +
  ggtitle("Distribución del Salario (Original)") +
  labs(x = "Salario (en miles de $)", y = "Frecuencia") +
  theme_minimal()

# La distribución está muy sesgada a la derecha. Aplicamos una transformación logarítmica para normalizarla.
ggplot(Hitters_clean, aes(x = log(Salary))) +
  geom_histogram(bins = 20, fill = "lightgreen", color = "black") +
  ggtitle("Distribución del Salario (Transformación Logarítmica)") +
  labs(x = "Log(Salario)", y = "Frecuencia") +
  theme_minimal()

# Seleccionamos solo las variables numéricas.
numeric_vars <- Hitters_clean %>% select_if(is.numeric)
cor_matrix <- cor(numeric_vars)

# Creamos una gráfica de la matriz de correlaciones.
corrplot(cor_matrix, method = "color", type = "upper", order = "hclust",
         addCoef.col = "black", number.cex = 0.6,
         tl.col = "black", tl.srt = 45)

# Boxplot de Salario por Liga (League)
ggplot(Hitters_clean, aes(x = League, y = Salary, fill = League)) +
  geom_boxplot() +
  ggtitle("Distribución del Salario por Liga") +
  theme_minimal()

# Boxplot de Salario por División (Division)
ggplot(Hitters_clean, aes(x = Division, y = Salary, fill = Division)) +
  geom_boxplot() +
  ggtitle("Distribución del Salario por División") +
  theme_minimal()

set.seed(123) # Semilla para reproducibilidad

train_indices <- sample(1:nrow(Hitters_clean), 0.7 * nrow(Hitters_clean))

train_data <- Hitters_clean[train_indices, ]
test_data <- Hitters_clean[-train_indices, ]

cat("Tamaño del set de entrenamiento:", nrow(train_data), "\n")
## Tamaño del set de entrenamiento: 184
cat("Tamaño del set de prueba:", nrow(test_data), "\n")
## Tamaño del set de prueba: 79
# La fórmula 'Salary ~ .' significa "predecir Salary usando todas las demás variables".
tree_full <- tree(Salary ~ ., data = train_data)

# Resumen del árbol
summary(tree_full)
## 
## Regression tree:
## tree(formula = Salary ~ ., data = train_data)
## Variables actually used in tree construction:
## [1] "CRBI"   "CAtBat" "AtBat"  "Walks"  "CRuns"  "CWalks"
## Number of terminal nodes:  10 
## Residual mean deviance:  64090 = 11150000 / 174 
## Distribution of residuals:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -669.30  -90.97  -29.20    0.00   86.78 1583.00
# Representación gráfica del árbol
plot(tree_full)
text(tree_full, pretty = 0, cex = 0.7)

set.seed(123) # Semilla para reproducibilidad
cv_tree <- cv.tree(tree_full)

# Graficamos el error vs. el tamaño del árbol.
plot(cv_tree$size, cv_tree$dev, type = "b",
     xlab = "Número de Nodos Finales (Hojas)",
     ylab = "Devianza (Error)",
     main = "Error de Validación Cruzada vs. Tamaño del Árbol")

# Identificamos el tamaño del árbol que minimiza el error.
best_size <- cv_tree$size[which.min(cv_tree$dev)]
cat("El tamaño óptimo del árbol según CV es:", best_size, "hojas.\n")
## El tamaño óptimo del árbol según CV es: 8 hojas.
# Podamos el árbol original al tamaño óptimo.
tree_pruned <- prune.tree(tree_full, best = best_size)

# Mostramos el árbol podado.
summary(tree_pruned)
## 
## Regression tree:
## snip.tree(tree = tree_full, nodes = c(12L, 4L))
## Variables actually used in tree construction:
## [1] "CRBI"   "CAtBat" "Walks"  "AtBat"  "CRuns"  "CWalks"
## Number of terminal nodes:  8 
## Residual mean deviance:  70350 = 12380000 / 176 
## Distribution of residuals:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -669.30 -111.70  -46.62    0.00   73.79 1939.00
plot(tree_pruned)
text(tree_pruned, pretty = 0, cex = 0.9)

# 1. Hacemos predicciones sobre el conjunto de prueba.
preds_tree <- predict(tree_pruned, newdata = test_data)

# 2. Calculamos el Error Cuadrático Medio (MSE).
mse_tree <- mean((test_data$Salary - preds_tree)^2)
cat("Error Cuadrático Medio (MSE) del árbol podado:", mse_tree, "\n")
## Error Cuadrático Medio (MSE) del árbol podado: 87409.28
# 3. Graficamos los valores reales vs. las predicciones.
ggplot(data = test_data, aes(x = Salary, y = preds_tree)) +
  geom_point(alpha = 0.6, color = "blue") +
  geom_abline(color = "red", linetype = "dashed", size = 1) + # Línea y=x (predicción perfecta)
  labs(title = "Valores Reales vs. Predicciones (Árbol Podado)",
       x = "Salario Real",
       y = "Salario Predicho") +
  theme_minimal()

set.seed(123) # Semilla para reproducibilidad
rf_model <- randomForest(Salary ~ ., data = train_data, ntree = 500, importance = TRUE)

# Hacemos predicciones con el modelo de Random Forest.
preds_rf <- predict(rf_model, newdata = test_data)

# Calculamos su MSE.
mse_rf <- mean((test_data$Salary - preds_rf)^2)

# Comparamos los resultados.
cat("MSE del Árbol de Decisión Podado:", mse_tree, "\n")
## MSE del Árbol de Decisión Podado: 87409.28
cat("MSE del Bosque Aleatorio:", mse_rf, "\n")
## MSE del Bosque Aleatorio: 62506.35
# Gráfica de importancia de variables
varImpPlot(rf_model, main = "Importancia de las Variables (Random Forest)")

# Extraemos los nombres de las 2 variables más importantes.
importance_df <- as.data.frame(importance(rf_model))
top_vars <- rownames(importance_df[order(-importance_df$`%IncMSE`), ])[1:2]
cat("Las 2 variables más importantes son:", top_vars[1], "y", top_vars[2], "\n")
## Las 2 variables más importantes son: CRuns y CHits
# Creamos la fórmula para el nuevo árbol.
formula_final <- as.formula(paste("Salary ~", paste(top_vars, collapse = " + ")))

# Ajustamos un árbol y lo podamos para que tenga exactamente 5 hojas.
tree_final_5leaves <- prune.tree(tree(formula_final, data = train_data), best = 5)

# Visualizamos este árbol simple.
plot(tree_final_5leaves)
text(tree_final_5leaves, pretty = 0)

# Usamos el árbol de 5 hojas para predecir la región de cada jugador en los datos de entrenamiento.
train_data$region <- as.factor(predict(tree_final_5leaves, newdata = train_data))

# Graficamos el scatter plot, coloreando los puntos por la región predicha.
ggplot(train_data, aes_string(x = top_vars[1], y = top_vars[2])) +
  geom_point(aes(color = region), alpha = 0.8, size = 3) +
  labs(title = "5 Regiones de Salario según las 2 Variables Más Importantes",
       x = top_vars[1],
       y = top_vars[2],
       color = "Salario Predicho\n(Región)") +
  theme_minimal()