Carga de datos

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.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
library(ggplot2)
library(readxl)
library(VIM)
## Loading required package: colorspace
## Loading required package: grid
## VIM is ready to use.
## 
## Suggestions and bug-reports can be submitted at: https://github.com/statistikat/VIM/issues
## 
## Attaching package: 'VIM'
## 
## The following object is masked from 'package:datasets':
## 
##     sleep
library(missForest)
## 
## Attaching package: 'missForest'
## 
## The following object is masked from 'package:VIM':
## 
##     nrmse
# Cargar datos
library(readxl)
dataset_logistica <- read_excel("Downloads/dataset_logistica.xlsx")
print(dataset_logistica)
## # A tibble: 30,000 × 31
##    peso_kg volumen_m3 tipo_producto fragilidad refrigerado distancia_km
##      <dbl>      <dbl> <chr>         <chr>      <chr>              <dbl>
##  1   14.7       0.185 Ropa          Media      No                  777.
##  2   39.5       1.56  Medicinas     Media      No                 2885.
##  3   20.7       0.570 Ropa          Media      Sí                 3040.
##  4   44.2       1.10  Electrónica   Baja       Sí                 3568.
##  5   47.1       0.397 Medicinas     Alta       No                 4824.
##  6    2.76      0.685 Muebles       Media      No                 2695.
##  7   26.6       1.67  Electrónica   Media      No                 4424.
##  8   44.7       0.701 Muebles       Baja       Sí                 1813.
##  9   27.8       1.47  Muebles       Baja       No                 2447.
## 10   23.1       0.350 Electrónica   Baja       No                 2204.
## # ℹ 29,990 more rows
## # ℹ 25 more variables: zona_destino <chr>, pais_destino <chr>,
## #   transportista <chr>, tipo_transporte <chr>, capacidad_carga_kg <dbl>,
## #   experiencia_conductor <dbl>, numero_reexpediciones <dbl>,
## #   tiempo_aduana_horas <dbl>, tiempo_procesamiento_horas <dbl>,
## #   tiempo_almacenamiento_horas <dbl>, ruta_optima <chr>, temporada <chr>,
## #   clima <chr>, temperatura_exterior <dbl>, volumen_envios_diarios <dbl>, …

Análisis Exploratorio de Datos

summary(dataset_logistica)
##     peso_kg          volumen_m3      tipo_producto       fragilidad       
##  Min.   : 0.5012   Min.   :0.01016   Length:30000       Length:30000      
##  1st Qu.:12.8412   1st Qu.:0.50472   Class :character   Class :character  
##  Median :24.9988   Median :0.99672   Mode  :character   Mode  :character  
##  Mean   :25.1582   Mean   :1.00149                                        
##  3rd Qu.:37.6170   3rd Qu.:1.49726                                        
##  Max.   :49.9971   Max.   :1.99998                                        
##  refrigerado         distancia_km      zona_destino       pais_destino      
##  Length:30000       Min.   :   5.017   Length:30000       Length:30000      
##  Class :character   1st Qu.:1234.339   Class :character   Class :character  
##  Mode  :character   Median :2479.251   Mode  :character   Mode  :character  
##                     Mean   :2483.756                                        
##                     3rd Qu.:3722.885                                        
##                     Max.   :5000.000                                        
##  transportista      tipo_transporte    capacidad_carga_kg experiencia_conductor
##  Length:30000       Length:30000       Min.   :  500.2    Min.   : 1.0         
##  Class :character   Class :character   1st Qu.: 5390.9    1st Qu.: 8.0         
##  Mode  :character   Mode  :character   Median :10246.0    Median :15.5         
##                                        Mean   :10241.3    Mean   :15.5         
##                                        3rd Qu.:15106.4    3rd Qu.:23.0         
##                                        Max.   :19999.9    Max.   :30.0         
##  numero_reexpediciones tiempo_aduana_horas tiempo_procesamiento_horas
##  Min.   :0.000         Min.   : 0.00228    Min.   : 1.000            
##  1st Qu.:1.000         1st Qu.:11.85423    1st Qu.: 6.752            
##  Median :2.000         Median :23.83309    Median :12.421            
##  Mean   :1.503         Mean   :23.82795    Mean   :12.456            
##  3rd Qu.:3.000         3rd Qu.:35.79505    3rd Qu.:18.167            
##  Max.   :3.000         Max.   :47.99778    Max.   :24.000            
##  tiempo_almacenamiento_horas ruta_optima         temporada        
##  Min.   : 0.00349            Length:30000       Length:30000      
##  1st Qu.:17.82581            Class :character   Class :character  
##  Median :35.89173            Mode  :character   Mode  :character  
##  Mean   :35.87662                                                 
##  3rd Qu.:53.83834                                                 
##  Max.   :71.99784                                                 
##     clima           temperatura_exterior volumen_envios_diarios
##  Length:30000       Min.   :-10.000      Min.   :  100.1       
##  Class :character   1st Qu.:  2.454      1st Qu.: 2588.2       
##  Mode  :character   Median : 15.056      Median : 5061.1       
##                     Mean   : 15.028      Mean   : 5067.5       
##                     3rd Qu.: 27.398      3rd Qu.: 7546.5       
##                     Max.   : 40.000      Max.   : 9999.9       
##  congestion_transito  costo_envio      seguro_envio       tipo_cliente      
##  Min.   : 0.0042     Min.   :  5.017   Length:30000       Length:30000      
##  1st Qu.:25.0910     1st Qu.:126.888   Class :character   Class :character  
##  Median :50.1110     Median :251.036   Mode  :character   Mode  :character  
##  Mean   :50.0673     Mean   :251.376                                        
##  3rd Qu.:75.0307     3rd Qu.:375.376                                        
##  Max.   :99.9875     Max.   :500.000                                        
##  devoluciones_previas nivel_satisfaccion_cliente numero_puntos_intermedios
##  Min.   :0.000        Min.   :1.000              Min.   :0.000            
##  1st Qu.:1.000        1st Qu.:3.258              1st Qu.:1.000            
##  Median :3.000        Median :5.538              Median :3.000            
##  Mean   :2.501        Mean   :5.520              Mean   :2.501            
##  3rd Qu.:4.000        3rd Qu.:7.762              3rd Qu.:4.000            
##  Max.   :5.000        Max.   :9.999              Max.   :5.000            
##  vehiculo_utilizado tiempo_entrega_horas categoria_entrega 
##  Length:30000       Min.   :-22.36       Length:30000      
##  Class :character   1st Qu.: 55.77       Class :character  
##  Mode  :character   Median :105.83       Mode  :character  
##                     Mean   :105.40                         
##                     3rd Qu.:154.85                         
##                     Max.   :232.19
ggplot(dataset_logistica, aes(x = categoria_entrega, fill = categoria_entrega)) + geom_bar() + theme_minimal()

ggplot(dataset_logistica, aes(x = tiempo_entrega_horas, fill = tiempo_entrega_horas)) + geom_histogram() + theme_minimal()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: The following aesthetics were dropped during statistical transformation: fill.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
##   the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?

# Calcular el porcentaje de filas con al menos un NA
porcentaje_filas_na <- sum(apply(dataset_logistica, 1, function(x) any(is.na(x)))) / nrow(dataset_logistica) * 100

# Mostrar el resultado
print(paste("Porcentaje de filas con valores NA:", round(porcentaje_filas_na, 2), "%"))
## [1] "Porcentaje de filas con valores NA: 4.31 %"
# Contar la cantidad de NAs en cada columna
na_por_columna <- colSums(is.na(dataset_logistica))

# Mostrar los resultados
print(na_por_columna)
##                     peso_kg                  volumen_m3 
##                           0                           0 
##               tipo_producto                  fragilidad 
##                           0                           0 
##                 refrigerado                distancia_km 
##                           0                           0 
##                zona_destino                pais_destino 
##                           0                           0 
##               transportista             tipo_transporte 
##                           0                           0 
##          capacidad_carga_kg       experiencia_conductor 
##                           0                           0 
##       numero_reexpediciones         tiempo_aduana_horas 
##                           0                           0 
##  tiempo_procesamiento_horas tiempo_almacenamiento_horas 
##                           0                           0 
##                 ruta_optima                   temporada 
##                           0                           0 
##                       clima        temperatura_exterior 
##                           0                           0 
##      volumen_envios_diarios         congestion_transito 
##                           0                           0 
##                 costo_envio                seguro_envio 
##                           0                           0 
##                tipo_cliente        devoluciones_previas 
##                           0                           0 
##  nivel_satisfaccion_cliente   numero_puntos_intermedios 
##                           0                           0 
##          vehiculo_utilizado        tiempo_entrega_horas 
##                           0                           0 
##           categoria_entrega 
##                        1294
# Eliminar filas con al menos un NA
dataset_sin_na <- na.omit(dataset_logistica)

# Verificar cuántas filas quedaron
print(paste("Filas originales:", nrow(dataset_logistica)))
## [1] "Filas originales: 30000"
print(paste("Filas después de eliminar NA:", nrow(dataset_sin_na)))
## [1] "Filas después de eliminar NA: 28706"
## Modelo de Regresión: Predicción de tiempo de entrega
set.seed(123)
trainIndex <- createDataPartition(dataset_sin_na$tiempo_entrega_horas, p = 0.8, list = FALSE)
trainData <- dataset_sin_na[trainIndex,]
testData <- dataset_sin_na[-trainIndex,]

# Modelos
lm_model <- lm(log(tiempo_entrega_horas) ~ ., data = trainData)
## Warning in log(tiempo_entrega_horas): NaNs produced
sum(is.na(trainData))
## [1] 0
trainData <- na.omit(trainData)

lm_pred <- predict(lm_model, testData)
lm_rmse <- sqrt(mean((lm_pred - testData$tiempo_entrega_horas)^2))
lm_rmse
## [1] 116.7289
 #Split the data into training and test sets
set.seed(123)  # Para reproducibilidad
data_split <- sample(1:nrow(dataset_sin_na), size = 0.7 * nrow(dataset_sin_na))
train_data <- dataset_sin_na[data_split, ]
test_data <- dataset_sin_na[-data_split, ]
 
# Crear el modelo Random Forest
rf_model_1 <- randomForest(tiempo_entrega_horas ~ ., data = train_data, ntree = 100)

# Realizar predicciones en el conjunto de prueba
predictions <- predict(rf_model_1, newdata = test_data)

rf_rsme <- sqrt(mean((predictions - test_data$tiempo_entrega_horas)^2))
print(rf_rsme)
## [1] 58.65953
## Modelo de Clasificación: Categoría de Entrega

# Split the data into training and test sets
set.seed(123)  # Para reproducibilidad
data_split <- sample(1:nrow(dataset_sin_na), size = 0.7 * nrow(dataset_sin_na))
train_data <- dataset_sin_na[data_split, ]
test_data <- dataset_sin_na[-data_split, ]
train_data$categoria_entrega <- as.factor(train_data$categoria_entrega)



# Crear el modelo Random Forest
rf_model <- randomForest(categoria_entrega ~ ., data = train_data, ntree = 100)

# Realizar predicciones en el conjunto de prueba
predictions <- predict(rf_model, newdata = test_data)

# Evaluar el modelo
confusion_matrix <- table(test_data$categoria_entrega, predictions)
print(confusion_matrix)
##            predictions
##             Normal Rápida Retrasada
##   Normal         1      0      2147
##   Rápida         1      0       693
##   Retrasada      5      0      5765
# Calcular la precisión
accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
print(paste("Precisión del modelo:", round(accuracy * 100, 2), "%"))
## [1] "Precisión del modelo: 66.95 %"