LATINCAR es una empresa destinada al transporte de carne en Latinoamérica. El transporte de carne bovina, tanto fresca como congelada, representa una de las operaciones más sensibles y complejas dentro de la cadena alimentaria sudamericana. El presente informe desarrolla el proceso de organización y logística aplicado al traslado de este producto a través de cinco países del continente: Perú, Uruguay, Argentina, Chile y Colombia. Cada país dispone de un almacén central que coordina la distribución hacia quince regiones internas, empleando cinco rutas optimizadas para reducir tiempos, costos y pérdidas por deterioro. La planificación logística de productos perecederos exige un equilibrio entre eficiencia operativa, control sanitario y sostenibilidad. En este estudio se adopta una metodología basada en la optimización de rutas mediante criterios de distancia mínima y mantenimiento de la cadena de frío. Se parte del supuesto de que cada país cuenta con un sistema nacional de transporte coordinado desde un almacén principal, desde donde se derivan rutas de distribución hacia las regiones designadas. El diseño de las rutas se apoya en modelos de optimización que buscan minimizar los kilómetros recorridos y el tiempo de transporte, considerando las limitaciones de capacidad vehicular, infraestructura y tiempos de conservación de la carne. Estas rutas se integran posteriormente en una red continental que permite la continuidad logística entre países y la conformación de un corredor sudamericano de distribución alimentaria.
Esta sección carga las librerías de R necesarias para el análisis. Se pueden desplegar los códigos presionando el botón “show”.
if (!requireNamespace("pacman", quietly = TRUE)) {
install.packages("pacman")
}
pacman::p_load(sf,
rio,
here,
janitor,
tidyverse,
dplyr,
magrittr,
ggplot2,
purrr,
lubridate,
mice,
plotly,
dplyr,
ggrepel,
ggplot2,
osrm,
DT,
htmltools,
leaflet,
htmlwidgets,
IRdisplay,
rnaturalearth,
sf,
geosphere,
kableExtra)
countries <- ne_countries(continent = "South America", returnclass = "sf")
selected_countries <- countries[countries$name %in% c("Uruguay",
"Argentina",# u otro país de LATAM
"Chile",
"Peru",
"Colombia"), ]
leaflet(data = selected_countries) %>%
addTiles() %>%
addPolygons(
fillColor = NA, # Sin relleno
color = "blue", # Color del contorno
weight = 2,
label = ~name
)
Argentina posee una amplia red de transporte terrestre que permite una distribución nacional eficiente, aunque con desafíos derivados de las largas distancias. La coordinación interregional se basa en plataformas logísticas intermedias que sirven como puntos de consolidación y redistribución. El sistema utiliza cinco rutas optimizadas para conectar las principales regiones productoras y de consumo. En Argentina, el almacén central se ubica en la ciudad de Junín, ubicada estratégicamente en la provincia de Buenos Aires con dirección a Mendoza.
A continuación se muestra la distribución de población en Argentina.
p_arg = data.frame(Customers = c(
"Buenos Aires","Córdoba","Rosario","Mendoza","La Plata",
"Mar del Plata","San Miguel de Tucumán","Salta","Santa Fe","San Juan",
"Resistencia","Neuquén","Bahía Blanca","Posadas","San Salvador de Jujuy"),
Latitude = c(
-34.6037,-31.4201,-32.9442,-32.8895,-34.9205,
-38.0055,-26.8083,-24.7821,-31.6333,-31.5375,
-27.4516,-38.9516,-38.7196,-27.3627,-24.1858),
Longitude = c(
-58.3816,-64.1888,-60.6505,-68.8458,-57.9536,
-57.5426,-65.2176,-65.4232,-60.7000,-68.5364,
-58.9867,-68.0591,-62.2724,-55.9009,-65.2995),
demand = c(3121707, # Ciudad Autónoma
1378682,1193605,937154,772618,682605,
548866,535303,417478,454173,291720,
340735,301501,397396,289867))
ggplot(p_arg, aes(x = Customers , y = demand)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(
title = "Argentina",
x = "",
y = "Población"
) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1)
)
argentina <- countries[countries$name %in% c("Argentina"), ]
leaflet(data = argentina) %>%
addTiles() %>%
addPolygons(
fillColor = "lightgreen",
color = "black",
weight = 2,
opacity = 1,
fillOpacity = 0.3
) %>%
addCircleMarkers(
data = p_arg,
lng = ~Longitude,
lat = ~Latitude,
radius = ~sqrt(demand)/100, # tamaño relativo a población
color = "red",
fillOpacity = 0.7,
label = ~paste0(Customers, ": ", demand)
)
El sistema colombiano presenta una estructura logística diversificada, con una red de transporte que conecta las principales regiones productoras con los centros de consumo. El almacén central se ubica en Buenaventura y administra quince nodos regionales, asegurando la trazabilidad de cada envío mediante sistemas digitales de control. Las rutas optimizadas priorizan la seguridad del transporte y la estabilidad térmica del producto.
A continuación se muestra la distribución de población en Colombia.
p_col = data.frame(Customers = c("Bogota","Medellin","cali","Barranquilla","cartagena de indias",
"cucuta","bucaramanga","pereira","santa marta","Ibagué",
"Manizales","Pasto","Neiva","Villavicencio","Monteria"),
Latitude = c(4.711, 6.2518, 3.4516, 10.9639,10.3910,
7.8939, 7.1193,4.8143,11.2408, 4.8143,
5.0703,1.2136, 2.9386,4.1420, 8.7480),
Longitude = c(-74.0721, -75.5636, -76.532, -74.7964, -75.4794,
-72.5078, -73.1227, -75.6946, -74.1990, -75.2322,
-75.5138, -77.2811, -75.2674, -73.6266, -75.8814),
demand = c(7937898,2533424,2285099,1279334,1065881,
812176,623881,482824,506184,526464,434403,
380581,363702,537251,505274))
ggplot(p_col, aes(x = Customers , y = demand)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(
title = "Colombia",
x = "",
y = "Población"
) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1)
)
colombia <- countries[countries$name %in% c("Colombia"), ]
leaflet(data = colombia) %>%
addTiles() %>%
addPolygons(
fillColor = "lightgreen",
color = "black",
weight = 2,
opacity = 1,
fillOpacity = 0.3
) %>%
addCircleMarkers(
data = p_col,
lng = ~Longitude,
lat = ~Latitude,
radius = ~sqrt(demand)/100, # tamaño relativo a población
color = "red",
fillOpacity = 0.7,
label = ~paste0(Customers, ": ", demand)
)
El sistema uruguayo se caracteriza por su escala manejable y un alto grado de trazabilidad en los procesos de transporte. Las rutas optimizadas permiten reducir significativamente los tiempos de entrega hacia las zonas más alejadas, priorizando la eficiencia energética y el mantenimiento de la cadena de frío. En el caso de Uruguay, el almacén central se ubica en la ciudad de Río Branco.
A continuación se muestra la distribución de población en Uruguay.
p_uy = data.frame(Customers = c("Montevideo","Salto","Paysandú","Rivera","Maldonado",
"Tacuarembó","Melo","Artigas","Mercedes","Durazno",
"Canelones","Florida","Rocha","San José","Colonia"),
Latitude = c(-34.9033, -31.3833, -32.3203, -30.9, -34.9,
-31.74, -32.37, -30.4, -33.23, -33.4,
-34.38, -33.6, -34.48, -34.34, -34.46),
Longitude = c(-56.1882, -57.9667, -58.0753, -55.55, -54.95,
-55.98, -54.18, -56.5, -58.03, -56.5,
-56.03, -56.23, -54.32, -56.71, -57.833),
demand = c(1380000, 124000, 76000, 64000, 63000,
54000, 52000, 41000, 41000, 36000,
33000, 33000, 26000, 27000, 27000))
ggplot(p_uy, aes(x = Customers , y = demand)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(
title = "Uruguay",
x = "",
y = "Población"
) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1)
)
uruguay <- countries[countries$name %in% c("Uruguay"), ]
leaflet(data = uruguay) %>%
addTiles() %>%
addPolygons(
fillColor = "lightgreen",
color = "black",
weight = 2,
opacity = 1,
fillOpacity = 0.3
) %>%
addCircleMarkers(
data = p_uy,
lng = ~Longitude,
lat = ~Latitude,
radius = ~sqrt(demand)/100, # tamaño relativo a población
color = "red",
fillOpacity = 0.7,
label = ~paste0(Customers, ": ", demand)
)
En Chile, el sistema logístico es un desafío por las limitaciones que impone el paisaje. Sse desarrolla de manera lineal a lo largo del eje norte-sur. El almacén central ubicado en Valparaiso supone fácil acceso al mar para la carne importada. Desde allí se coordina la distribución hacia las regiones mediante cinco rutas que cubren zonas con distintas condiciones climáticas y topográficas. La gestión del transporte considera la programación temporal para evitar interrupciones en la cadena de frío y optimizar la capacidad de los vehículos refrigerados.
A continuación se muestra la distribución de población en Chile.
p_cl <- data.frame(
Customers = c("Santiago","Valparaíso","Concepción","La Serena","Antofagasta",
"Temuco","Rancagua","Arica","Iquique","Puerto Montt",
"Coyhaique","Punta Arenas","Talca","Chillán","Osorno"),
Latitude = c(-33.4489, -33.0458, -36.8260, -29.9027, -23.6500,
-38.7359, -34.1701, -18.4783, -20.2133, -41.4693,
-45.5712, -53.1638, -35.4264, -36.6066, -40.5740),
Longitude = c(-70.6693, -71.6197, -73.0498, -71.2520, -70.4000,
-72.5904, -70.7406, -70.3126, -70.1510, -72.9424,
-72.0683, -70.9171, -71.6554, -72.1034, -73.1333),
demand = c(6500000, 970000, 900000, 250000, 400000,
280000, 250000, 230000, 220000, 220000,
60000, 130000, 220000, 180000, 160000)
)
ggplot(p_cl, aes(x = Customers , y = demand)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(
title = "Chile",
x = "",
y = "Población"
) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1)
)
chile <- countries[countries$name %in% c("Chile"), ]
leaflet(data = chile) %>%
addTiles() %>%
addPolygons(
fillColor = "lightgreen",
color = "black",
weight = 2,
opacity = 1,
fillOpacity = 0.3
) %>%
addCircleMarkers(
data = p_cl,
lng = ~Longitude,
lat = ~Latitude,
radius = ~sqrt(demand)/100, # tamaño relativo a población
color = "red",
fillOpacity = 0.7,
label = ~paste0(Customers, ": ", demand)
)
En Perú, la organización logística se estructura en torno a un almacén central ubicado en el Callao, cerca de la ciudad de Lima. Desde allí se que coordina el suministro hacía quince regiones nacionales del Perú. Cada región cuenta con instalaciones de recepción refrigerada que aseguran la conservación del producto antes de su redistribución. Las cinco rutas principales optimizadas se establecen considerando la accesibilidad geográfica y la disponibilidad de infraestructura vial.
A continuación se muestra la distribución de población en Perú.
p_pe<- data.frame(
Customers = c("Lima", "Arequipa", "Trujillo", "Piura", "La Libertad",
"Cusco", "Ica", "Huancayo", "Tacna", "Puno",
"Pisco", "Chincha", "Cañete", "Huamanga", "Moquegua"),
Latitude = c(-12.0464, -16.3989, -8.1150, -5.1945, -8.1140,
-13.5200, -14.0678, -12.0651, -18.0110, -15.8400,
-13.7100, -13.4100, -13.0833, -13.1600, -17.1900),
Longitude = c(-77.0428, -71.5350, -79.0290, -80.6328, -79.0200,
-71.9670, -75.7286, -75.2049, -70.2510, -70.0219,
-76.2000, -76.1300, -76.3833, -74.2200, -70.9300),
demand = c(10000000, 1500000, 1100000, 1800000, 800000,
1400000, 850000, 500000, 300000, 400000,
135000, 180000, 200000, 190000, 130000)
)
ggplot(p_pe, aes(x = Customers , y = demand)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(
title = "Perú",
x = "",
y = "Población"
) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1)
)
peru <- countries[countries$name %in% c("Peru"), ]
leaflet(data = peru) %>%
addTiles() %>%
addPolygons(
fillColor = "lightgreen",
color = "black",
weight = 2,
opacity = 1,
fillOpacity = 0.3
) %>%
addCircleMarkers(
data = p_pe,
lng = ~Longitude,
lat = ~Latitude,
radius = ~sqrt(demand)/100, # tamaño relativo a población
color = "red",
fillOpacity = 0.7,
label = ~paste0(Customers, ": ", demand)
)
La demanda de carne se estima en función de la población de cada ciudad. Se asume que las preferencias alimentarias son homogéneas y no varían entre los habitantes de los distintos países ni según su poder adquisitivo.
ppp = data.frame(pais = c("Argentina","Colombia",
"Chile","Perú","Uruguay"),
poblacion = c(sum(p_arg$demand),
sum(p_col$demand),
sum(p_cl$demand),
sum(p_pe$demand),
sum(p_uy$demand)))
ggplot(ppp, aes(x = pais , y = poblacion)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(
#title = "Perú",
x = "",
y = "Población"
) +
theme(
legend.position = "none",
axis.text.x = element_text(angle = 45, hjust = 1)
)
Los países tienen demandas diferentes, siendo la más baja en Uruguay y la más grande en Colombia. Esto tiene un impacto en la cantidad de unidades de transporte necesarias para realizar el reparto en cada País. Por ello, se organizó la capacidad de transporte de forma independiente para garantizar que la cantidad de rutas de transporte sea igual en cada país. Esto resultó en que el tamaño del transporte con respecto al transporte en Uruguay es 10x en Argentina, 14x en Colombia, 6x en Chile y 12x en Perú.
Esta sección muestra las rutas que unen los centros de almacenamiento de los diferentes países. Se unen las ciudades de Callao (Perú), Río Branco (Uruguay), Buenaventura (Colombia), Valparaiso (Chile), y Junín (Argentina).
Se definen rutas o segmentos nacionales desde el almacén principal de cada país hasta cada paso de frontera para luego proseguir con el siguiente almacén. Dada la orientación Sur - Norte de América Latina, la ruta internacional deberá seguir Uruguay - Argentina - Chile - Perú - Ecuador - Colombia (sin reparto en Ecuador).
A continuación se muestra la ruta internacional.
# Datos de los centros
centros <- data.frame(
centro = c("Río Branco","frontera_uy_arg",
"frontera_arg_uy","Junin","frontera_arg_cl",
"frontera_cl_arg", "Valparaiso","frontera_cl_pe",
"frontera_pe_cl", "Callao", "frontera_pe_ec",
"frontera_ec_pe","frontera_ec_co",
"frontera_co_ec","Buenaventura"),
Lat = c(-32.593974,-33.112735,
-33.048953,-34.59391,-32.805697,
-32.825959,-33.038600,-18.322781,-18.303299,-12.055,
-3.498951,-3.497077,0.813607,0.814957,3.8801),
Long = c(-53.3824927,-58.245700,
-58.260066,-60.946447,-70.074931,
-70.092261,-71.605000,-70.312924,-70.314950,-77.135,
-80.239946,-80.220764,-77.664874,-77.661718,-77.0312)
)
new_manufacturer <- data.frame(Lat = c(-32.593974),
Long = c(-53.3824927))
# Convertir a sf
centros_sf <- st_as_sf(centros, coords = c("Long", "Lat"), crs = 4326)
# Crear una lista para guardar las rutas
rutas_list <- list()
# Calcular rutas consecutivas
for (i in 1:(nrow(centros_sf)-1)) {
ruta <- try(osrmRoute(src = centros_sf[i,],
dst = centros_sf[i+1,],
overview = "full", returnclass = "sf"), silent = TRUE)
if (!inherits(ruta, "try-error")) {
rutas_list[[i]] <- ruta
}
}
# Unir todas las rutas en un solo objeto sf
rutas_sf <- do.call(rbind, rutas_list)
# Mapa interactivo
leaflet() %>%
addTiles() %>%
addPolylines(data = rutas_sf, color = "blue", weight = 3, opacity = 0.7) %>%
addCircleMarkers(data = centros_sf, label = ~centro,
color = "red", radius = 5, fillOpacity = 0.8)
# función Haversine (km)
haversine_km <- function(lat1, lon1, lat2, lon2) {
geosphere::distHaversine(c(lon1, lat1), c(lon2, lat2)) / 1000
}
# preparar pares consecutivos
pairs <- tibble(
from = centros$centro[-nrow(centros)],
to = centros$centro[-1],
from_lat = centros$Lat[-nrow(centros)],
from_long = centros$Long[-nrow(centros)],
to_lat = centros$Lat[-1],
to_long = centros$Long[-1]
)
# intentar obtener distancia por carretera con OSRM (si falla, NA)
pairs <- pairs %>%
rowwise() %>%
mutate(
osrm_res = list(tryCatch(
osrm::osrmRoute(src = data.frame(id = from, lon = from_long, lat = from_lat),
dst = data.frame(id = to, lon = to_long, lat = to_lat),
overview = "false", returnclass = "sf"),
error = function(e) NULL)),
distance_osrm_km = if (!is.null(osrm_res) && "distance" %in% names(osrm_res)) {
osrm_res$distance/1000
} else if (!is.null(osrm_res) && !is.null(attr(osrm_res, "route")) && !is.null(osrm_res$distance)) {
osrm_res$distance/1000
} else {
NA_real_
},
distance_haversine_km = haversine_km(from_lat, from_long, to_lat, to_long)
) %>%
ungroup() %>%
select(from, to, distance_osrm_km, distance_haversine_km)
kable(pairs[,c(1,2,4)],
col.names = c("desde", "hasta", "distancia"),
digits = 1)
| desde | hasta | distancia |
|---|---|---|
| Río Branco | frontera_uy_arg | 458.4 |
| frontera_uy_arg | frontera_arg_uy | 7.2 |
| frontera_arg_uy | Junin | 302.1 |
| Junin | frontera_arg_cl | 868.2 |
| frontera_arg_cl | frontera_cl_arg | 2.8 |
| frontera_cl_arg | Valparaiso | 143.3 |
| Valparaiso | frontera_cl_pe | 1643.2 |
| frontera_cl_pe | frontera_pe_cl | 2.2 |
| frontera_pe_cl | Callao | 1009.9 |
| Callao | frontera_pe_ec | 1012.0 |
| frontera_pe_ec | frontera_ec_pe | 2.1 |
| frontera_ec_pe | frontera_ec_co | 557.8 |
| frontera_ec_co | frontera_co_ec | 0.4 |
| frontera_co_ec | Buenaventura | 348.3 |
A continuación se crean las funciones necesarias para el calculo de rutas
# Giant_path function for the Hamiltonian Cycle:
giant_path <- function(distance, demand){
visited_spot <- NULL
vehicle_num <- 1
post <- 1:ncol(distance)
names(demand) <- 1:length(demand)
# Randomly select initial spot
initial_spot <- sample(2:length(demand), 1)
while (any(demand != 0)) {
available_spot <- which(demand != 0)
# Calculate the distance to unvisited spot
initial_dist <- distance[ c(available_spot), initial_spot]
initial_dist <- initial_dist[ which(names(initial_dist) != initial_spot)]
visited_spot <- c(visited_spot, initial_spot)
demand[ initial_spot ] <- 0
if ( length(initial_dist)>1) {
initial_spot <- which(initial_dist == min(initial_dist)) %>% names() %>% as.numeric()
} else {
initial_spot <- which(demand != 0)
}
}
visited_spot <- c(1, visited_spot, 1)
names(visited_spot) <- NULL
total_distance <- embed(visited_spot, 2)[ , 2:1] %>% distance[.] %>% sum()
result <- list(route = visited_spot,
total_distance = total_distance)
return(result)
}
# Assign Vehicle function to assign the route:
assign_vehicle <- function(x, demand, capacity, distance){
vehicle_load <- capacity
visited_spot <- NULL
vehicle_num <- 1
for (i in x) {
initial_spot <- i
if (vehicle_load >= demand[i]) {
visited_spot <- c(visited_spot, initial_spot)
vehicle_load <- vehicle_load - demand[ initial_spot ]
} else {
# Go back to depot
vehicle_num <- vehicle_num + 1
vehicle_load <- capacity
visited_spot <- c(visited_spot, 1)
# Revisit the spot
visited_spot <- c(visited_spot, initial_spot)
vehicle_load <- vehicle_load - demand[ initial_spot ]
}
}
visited_spot <- c(visited_spot)
total_distance <- embed(visited_spot, 2)[ , 2:1] %>% distance[.] %>% sum()
return(list(distance = total_distance,
route = visited_spot,
num_vehicle = vehicle_num))
}
#Fitness function for ga method:
fitness <- function(x, capacity, demand, distance, ...){
vehicle_load <- capacity
visited_spot <- 1
vehicle_num <- 1
for (i in x) {
initial_spot <- i
if (vehicle_load > demand[initial_spot]) {
# Go to the spot
visited_spot <- c(visited_spot, initial_spot)
vehicle_load <- vehicle_load - demand[ initial_spot ]
} else {
# Go back to depot
vehicle_load <- capacity
visited_spot <- c(visited_spot, 1)
vehicle_num <- vehicle_num + 1
# Go to the spot
visited_spot <- c(visited_spot, initial_spot)
vehicle_load <- vehicle_load - demand[ initial_spot ]
}
}
visited_spot <- c(visited_spot, 1)
total_distance <- embed(visited_spot, 2)[ , 2:1] %>% distance[.] %>% sum()
return(-total_distance)
}
fitness_explain <- function(x, capacity, demand, distance, ...){
vehicle_load <- capacity
visited_spot <- 1
vehicle_num <- 1
total_demand <- NULL
for (i in x) {
initial_spot <- i
if (vehicle_load > demand[initial_spot]) {
# Go to the spot
visited_spot <- c(visited_spot, initial_spot)
vehicle_load <- vehicle_load - demand[ initial_spot ]
} else {
total_demand <- c(total_demand, 6000 - vehicle_load)
# Go back to depot
vehicle_load <- capacity
visited_spot <- c(visited_spot, 1)
vehicle_num <- vehicle_num + 1
# Go to the spot
visited_spot <- c(visited_spot, initial_spot)
vehicle_load <- vehicle_load - demand[ initial_spot ]
}
}
total_demand <- c(total_demand, 6000 - vehicle_load)
visited_spot <- c(visited_spot, 1)
total_distance <- embed(visited_spot, 2)[ , 2:1] %>% distance[.] %>% sum()
result <- list(route = visited_spot,
total_distance = total_distance,
vehicle_num = vehicle_num,
total_demand = total_demand)
return(result)
}
Se supone el almacén de despacho en de mercancías en Junín con coordenadas −34.59391 latitud y −60.94644 longitud.
MyData = p_arg
new_manufacturer <- data.frame(Lat = c(-34.59391),
Long = c(-60.946447))
## Crear un dataframe (route) que incluya este punto y unirlo con los datos de Mydata:
route <- data.frame("Manufacturer",
new_manufacturer[,c("Long","Lat")],
0)
colnames(route) <- c("Customers",
"Longitude",
"Latitude",
"demand")
route <- rbind(route,
MyData%>% select(Customers,
Longitude,
Latitude,
demand))
## Crear un índice con el id de los nodos a procesar:
route$node <- 1:nrow(route)
La matriz de distancias se calcula utilizando las funciones previamente definidas.
route_distance <- dist(route[ ,c("Longitude","Latitude")],
upper = T,
diag = T) %>%
as.matrix()
# Calcular mejor ruta:
best_route <- list(total_distance = Inf)
for (i in 1:10^4) {
try_route <- giant_path(demand = route$demand,
distance = route_distance)
if (best_route$total_distance > try_route$total_distance) {
best_route <- try_route
}
}
El calculo de las mejores rutas se realiza con la función \(assing_vehicule\).
La demanda es escalada en todos los países por igual. Para el caso de Argentina, la capacidad de transporte se aumenta por el factor de 10x, esto compensa la mayor demanda al tener más población.
nearest_result <- assign_vehicle(x = best_route$route,
demand = route$demand/10,
capacity = 30000*10,
distance = route_distance)
# Listado de nodos de las rutas identificadas
nearest_result
## $distance
## [1] 85.01986
##
## $route
## [1] 1 10 4 1 2 1 6 7 14 13 1 5 11 3 1 8 9 16 12 15 1
##
## $num_vehicle
## [1] 5
El mapa vectorial se realiza sin mapa de fondo utilizando la librería ggplot2.
nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
rename(from_x1 = Longitude,
from_x2 = Latitude) %>%
left_join(route,
by = c("to" = "node")) %>%
rename(to_x1 = Longitude,
to_x2 = Latitude) %>%
rename(demand = demand.y) %>%
select(-demand.x) %>%
mutate(unit = c( rep("A", 3), # linea modificada para coincidir nodos
rep("B",2), # linea modificada para coincidir nodos
rep("C", 5), # linea modificada para coincidir nodos
rep("D", 4), # linea modificada para coincidir nodos
rep("E",6))) %>% # linea modificada para coincidir nodos
ggplot() +
geom_point(data = route,
aes(Longitude,
Latitude),
show.legend = F) +
geom_curve(aes(x = from_x1,
xend = to_x1,
y = from_x2,
yend = to_x2,
color = unit),
curvature = -0.05,
size = 0.3,
alpha = 0.6,
arrow = arrow(type = "closed",
angle = 30,
length = unit(3, "mm")) ) +
geom_point(data = route[1,],
aes(Longitude,
Latitude),
color = "red",
size = 2) +
geom_label_repel(data = route,
aes(Longitude,
Latitude,
label = node),
alpha = 0.6,
max.overlaps = Inf,
size=1) +
scale_color_manual(values = c("firebrick",
"orange",
"dodgerblue",
"green3",
"purple"))+
theme_minimal() +
theme(panel.grid = element_blank()) +
theme(legend.position = "top") +
labs(x = quote(x[1]),
y = quote(x[2]),
title = "Problema de ruta del vehículo con el vecino más cercano",
subtitle = "Capacidad del vehículo = 30000",
color = "Ruta")
Las rutas de Argentina se presentan en la siguiente tabla.
df<-nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
mutate(unit = c( rep("A", 3), # linea modificada para coincidir nodos
rep("B",2), # linea modificada para coincidir nodos
rep("C", 5), # linea modificada para coincidir nodos
rep("D", 4), # linea modificada para coincidir nodos
rep("E",6))) # linea modificada para coincidir nodos
dfA<-df %>% filter(unit == "A")
tripA <- osrmTrip(dfA[,c("Longitude","Latitude")],
overview = "full")
dfB<-df %>% filter(unit == "B")
tripB <- osrmTrip(dfB[,c("Longitude","Latitude")],
overview = "full")
dfC<-df %>% filter(unit == "C")
tripC <- osrmTrip(dfC[,c("Longitude","Latitude")],
overview = "full")
dfD<-df %>% filter(unit == "D")
tripD <- osrmTrip(dfD[,c("Longitude","Latitude")],
overview = "full")
dfE<-df %>% filter(unit == "E")
tripE <- osrmTrip(dfE[,c("Longitude","Latitude")],
overview = "full")
##Crear matriz para resumen:
summary = matrix(c(as.numeric(tripA[[1]]$summary),
as.numeric(tripB[[1]]$summary),
as.numeric(tripC[[1]]$summary),
as.numeric(tripD[[1]]$summary),
as.numeric(tripE[[1]]$summary)),
ncol = 2,
nrow = 5,
byrow = T)
summary[,1] = summary[,1]/60
summary = round(summary,1)
colnames(summary) = c("Duracion (h)","Distancia (km)")
rownames(summary) = c("Trip A","Trip B","Trip C","Trip D","Trip E")
#library(DT)
datatable(summary)
El mapa dinámico con las 5 rutas de Argentina se presenta a continuación.
#Create labels:
labels<- paste0("<strong> Customers </strong> ",
MyData$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
MyData$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
MyData$Latitude, "<br/> ",
"<strong> demand </strong> ",
MyData$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = MyData$Longitude,
lat = MyData$Latitude,
label = ~labels) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick") %>%
addPolylines(data = tripB[[1]]$trip,
label = "Trip B",
color = "orange") %>%
addPolylines(data = tripC[[1]]$trip,
label = "Trip C",
color = "dodgerblue") %>%
addPolylines(data = tripD[[1]]$trip,
label = "Trip D",
color = "red") %>%
addPolylines(data = tripE[[1]]$trip,
label = "Trip E",
color = "purple")
Si se desea consultar una única ruta con marcadores, se tiene:
labels2<- paste0("<strong> Customers </strong> ",
dfA$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
dfA$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
dfA$Latitude, "<br/> ",
"<strong> demand </strong> ",
dfA$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = dfA$Longitude,
lat = dfA$Latitude,
label = ~labels2) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick")
Se supone almacén de despacho en de mercancías en Buenaventura con coordenadas 3.8801 latitud y -77.0312 longitud
MyData = p_col
new_manufacturer <- data.frame(Lat = c(3.8801),
Long = c(-77.0312))
## Crear un dataframe (route) que incluya este punto y unirlo con los datos de Mydata:
route <- data.frame("Manufacturer",
new_manufacturer[,c("Long","Lat")],
0)
colnames(route) <- c("Customers",
"Longitude",
"Latitude",
"demand")
route <- rbind(route,
MyData%>% select(Customers,
Longitude,
Latitude,
demand))
## Crear un índice con el id de los nodos a procesar:
route$node <- 1:nrow(route)
La matriz de distancias se calcula a continuación:
route_distance <- dist(route[ ,c("Longitude","Latitude")],
upper = T,
diag = T) %>%
as.matrix()
# Calcular mejor ruta:
best_route <- list(total_distance = Inf)
for (i in 1:10^4) {
try_route <- giant_path(demand = route$demand,
distance = route_distance)
if (best_route$total_distance > try_route$total_distance) {
best_route <- try_route
}
}
Luego, las mejores rutas para Colombia se calculan con el mismo principio de dividir la demanda entre 10 y escalar la capacidad de los transportes. Para Colombia, el factor de escala en capacidad fue 14, lo que produce 5 rutas de despacho.
nearest_result <- assign_vehicle(x = best_route$route,
demand = route$demand/10,
capacity = 30000*14,
distance = route_distance)
# Listado de nodos de las rutas identificadas
nearest_result
## $distance
## [1] 54.14853
##
## $route
## [1] 1 15 1 2 1 11 12 9 3 1 16 6 5 10 7 1 8 14 4 13 1
##
## $num_vehicle
## [1] 5
El mapa de estas 5 rutas se calcula siguiendo el mismo procedimiento:
nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
rename(from_x1 = Longitude,
from_x2 = Latitude) %>%
left_join(route,
by = c("to" = "node")) %>%
rename(to_x1 = Longitude,
to_x2 = Latitude) %>%
rename(demand = demand.y) %>%
select(-demand.x) %>%
mutate(unit = c( rep("A", 2), # linea modificada para coincidir nodos
rep("B",2), # linea modificada para coincidir nodos
rep("C", 6), # linea modificada para coincidir nodos
rep("D", 6), # linea modificada para coincidir nodos
rep("E",4))) %>% # linea modificada para coincidir nodos
ggplot() +
geom_point(data = route,
aes(Longitude,
Latitude),
show.legend = F) +
geom_curve(aes(x = from_x1,
xend = to_x1,
y = from_x2,
yend = to_x2,
color = unit),
curvature = -0.05,
size = 0.3,
alpha = 0.6,
arrow = arrow(type = "closed",
angle = 30,
length = unit(3, "mm")) ) +
geom_point(data = route[1,],
aes(Longitude,
Latitude),
color = "red",
size = 2) +
geom_label_repel(data = route,
aes(Longitude,
Latitude,
label = node),
alpha = 0.6,
max.overlaps = Inf,
size=1) +
scale_color_manual(values = c("firebrick",
"orange",
"dodgerblue",
"green3",
"purple"))+
theme_minimal() +
theme(panel.grid = element_blank()) +
theme(legend.position = "top") +
labs(x = quote(x[1]),
y = quote(x[2]),
title = "Problema de ruta del vehículo con el vecino más cercano",
subtitle = "Capacidad del vehículo = 30000",
color = "Ruta")
La tabla con las mejores rutas queda:
df<-nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
mutate(unit = c( rep("A", 2), # linea modificada para coincidir nodos
rep("B",2), # linea modificada para coincidir nodos
rep("C", 6), # linea modificada para coincidir nodos
rep("D", 6), # linea modificada para coincidir nodos
rep("E",4))) # linea modificada para coincidir nodos
dfA<-df %>% filter(unit == "A")
tripA <- osrmTrip(dfA[,c("Longitude","Latitude")],
overview = "full")
dfB<-df %>% filter(unit == "B")
tripB <- osrmTrip(dfB[,c("Longitude","Latitude")],
overview = "full")
dfC<-df %>% filter(unit == "C")
tripC <- osrmTrip(dfC[,c("Longitude","Latitude")],
overview = "full")
dfD<-df %>% filter(unit == "D")
tripD <- osrmTrip(dfD[,c("Longitude","Latitude")],
overview = "full")
dfE<-df %>% filter(unit == "E")
tripE <- osrmTrip(dfE[,c("Longitude","Latitude")],
overview = "full")
##Crear matriz para resumen:
summary = matrix(c(as.numeric(tripA[[1]]$summary),
as.numeric(tripB[[1]]$summary),
as.numeric(tripC[[1]]$summary),
as.numeric(tripD[[1]]$summary),
as.numeric(tripE[[1]]$summary)),
ncol = 2,
nrow = 5,
byrow = T)
summary[,1] = summary[,1]/60
summary = round(summary,1)
colnames(summary) = c("Duracion (h)","Distancia (km)")
rownames(summary) = c("Trip A","Trip B","Trip C","Trip D","Trip E")
#library(DT)
datatable(summary)
El mapa dinámico de Colombia es:
#Create labels:
labels<- paste0("<strong> Customers </strong> ",
MyData$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
MyData$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
MyData$Latitude, "<br/> ",
"<strong> demand </strong> ",
MyData$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = MyData$Longitude,
lat = MyData$Latitude,
label = ~labels) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick") %>%
addPolylines(data = tripB[[1]]$trip,
label = "Trip B",
color = "orange") %>%
addPolylines(data = tripC[[1]]$trip,
label = "Trip C",
color = "dodgerblue") %>%
addPolylines(data = tripD[[1]]$trip,
label = "Trip D",
color = "red") %>%
addPolylines(data = tripE[[1]]$trip,
label = "Trip E",
color = "purple")
Luego, una única ruta con sus marcadores sigue la forma:
labels2<- paste0("<strong> Customers </strong> ",
dfA$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
dfA$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
dfA$Latitude, "<br/> ",
"<strong> demand </strong> ",
dfA$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = dfA$Longitude,
lat = dfA$Latitude,
label = ~labels2) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick")
Se supone un almacén de despacho en de mercancías en Río Branco (frontera con Brasil) con coordenadas -32.593974 latitud y -53.382492 longitud
MyData = p_uy
new_manufacturer <- data.frame(Lat = c(-32.593974),
Long = c(-53.3824927))
## Crear un dataframe (route) que incluya este punto y unirlo con los datos de Mydata:
route <- data.frame("Manufacturer",
new_manufacturer[,c("Long","Lat")],
0)
colnames(route) <- c("Customers",
"Longitude",
"Latitude",
"demand")
route <- rbind(route,
MyData%>% select(Customers,
Longitude,
Latitude,
demand))
## Crear un índice con el id de los nodos a procesar:
route$node <- 1:nrow(route)
La matriz de distancias:
route_distance <- dist(route[ ,c("Longitude","Latitude")],
upper = T,
diag = T) %>%
as.matrix()
# Calcular mejor ruta:
best_route <- list(total_distance = Inf)
for (i in 1:10^4) {
try_route <- giant_path(demand = route$demand,
distance = route_distance)
if (best_route$total_distance > try_route$total_distance) {
best_route <- try_route
}
}
Las mejores rutas limitadas por capacidad, la demanda es dividida entre 10 (igual que en todos los países) y el factor de escala para la capacidad de los camiones es 1 (Uruguay es el patrón de escala). Esta configuración produce 5 rutas.
nearest_result <- assign_vehicle(x = best_route$route,
demand = route$demand/10,
capacity = 30000,
distance = route_distance)
# Listado de nodos de las rutas identificadas
nearest_result
## $distance
## [1] 44.15257
##
## $route
## [1] 1 8 7 5 9 1 3 4 10 16 15 1 12 1 2 1 6 14 13 11 1
##
## $num_vehicle
## [1] 5
El mapa vectorial de rutas queda:
nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
rename(from_x1 = Longitude,
from_x2 = Latitude) %>%
left_join(route,
by = c("to" = "node")) %>%
rename(to_x1 = Longitude,
to_x2 = Latitude) %>%
rename(demand = demand.y) %>%
select(-demand.x) %>%
mutate(unit = c( rep("A", 5), # linea modificada para coincidir nodos
rep("B",6), # linea modificada para coincidir nodos
rep("C", 2), # linea modificada para coincidir nodos
rep("D", 2), # linea modificada para coincidir nodos
rep("E",5))) %>% # linea modificada para coincidir nodos
ggplot() +
geom_point(data = route,
aes(Longitude,
Latitude),
show.legend = F) +
geom_curve(aes(x = from_x1,
xend = to_x1,
y = from_x2,
yend = to_x2,
color = unit),
curvature = -0.05,
size = 0.3,
alpha = 0.6,
arrow = arrow(type = "closed",
angle = 30,
length = unit(3, "mm")) ) +
geom_point(data = route[1,],
aes(Longitude,
Latitude),
color = "red",
size = 2) +
geom_label_repel(data = route,
aes(Longitude,
Latitude,
label = node),
alpha = 0.6,
max.overlaps = Inf,
size=1) +
scale_color_manual(values = c("firebrick",
"orange",
"dodgerblue",
"green3",
"purple"))+
theme_minimal() +
theme(panel.grid = element_blank()) +
theme(legend.position = "top") +
labs(x = quote(x[1]),
y = quote(x[2]),
title = "Problema de ruta del vehículo con el vecino más cercano",
subtitle = "Capacidad del vehículo = 30000",
color = "Ruta")
A continuación se presenta la tabla con las características de cada ruta:
df<-nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
mutate(unit = c( rep("A", 5), # linea modificada para coincidir nodos
rep("B",6), # linea modificada para coincidir nodos
rep("C", 2), # linea modificada para coincidir nodos
rep("D", 2), # linea modificada para coincidir nodos
rep("E",5))) # linea modificada para coincidir nodos
dfA<-df %>% filter(unit == "A")
tripA <- osrmTrip(dfA[,c("Longitude","Latitude")],
overview = "full")
dfB<-df %>% filter(unit == "B")
tripB <- osrmTrip(dfB[,c("Longitude","Latitude")],
overview = "full")
dfC<-df %>% filter(unit == "C")
tripC <- osrmTrip(dfC[,c("Longitude","Latitude")],
overview = "full")
dfD<-df %>% filter(unit == "D")
tripD <- osrmTrip(dfD[,c("Longitude","Latitude")],
overview = "full")
dfE<-df %>% filter(unit == "E")
tripE <- osrmTrip(dfE[,c("Longitude","Latitude")],
overview = "full")
##Crear matriz para resumen:
summary = matrix(c(as.numeric(tripA[[1]]$summary),
as.numeric(tripB[[1]]$summary),
as.numeric(tripC[[1]]$summary),
as.numeric(tripD[[1]]$summary),
as.numeric(tripE[[1]]$summary)),
ncol = 2,
nrow = 5,
byrow = T)
summary[,1] = summary[,1]/60
summary = round(summary,1)
colnames(summary) = c("Duracion (h)","Distancia (km)")
rownames(summary) = c("Trip A","Trip B","Trip C","Trip D","Trip E")
#library(DT)
datatable(summary)
El mapa dinamico se muestra a continuación:
#Create labels:
labels<- paste0("<strong> Customers </strong> ",
MyData$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
MyData$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
MyData$Latitude, "<br/> ",
"<strong> demand </strong> ",
MyData$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = MyData$Longitude,
lat = MyData$Latitude,
label = ~labels) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick") %>%
addPolylines(data = tripB[[1]]$trip,
label = "Trip B",
color = "orange") %>%
addPolylines(data = tripC[[1]]$trip,
label = "Trip C",
color = "dodgerblue") %>%
addPolylines(data = tripD[[1]]$trip,
label = "Trip D",
color = "red") %>%
addPolylines(data = tripE[[1]]$trip,
label = "Trip E",
color = "purple")
Luego, una única ruta con marcadores se tiene:
labels2<- paste0("<strong> Customers </strong> ",
dfA$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
dfA$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
dfA$Latitude, "<br/> ",
"<strong> demand </strong> ",
dfA$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = dfA$Longitude,
lat = dfA$Latitude,
label = ~labels2) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick")
En Chile se reparte desde Valparaiso, lo que supone fácil acceso al mar estando ubicado en un punto medio en la geografía.
MyData = p_cl
new_manufacturer <- data.frame(Lat = -33.038600,
Long = -71.605000) # cerca de Valparaíso
## Crear un dataframe (route) que incluya este punto y unirlo con los datos de Mydata:
route <- data.frame("Manufacturer",
new_manufacturer[,c("Long","Lat")],
0)
colnames(route) <- c("Customers",
"Longitude",
"Latitude",
"demand")
route <- rbind(route,
MyData%>% select(Customers,
Longitude,
Latitude,
demand))
## Crear un índice con el id de los nodos a procesar:
route$node <- 1:nrow(route)
La matriz de distancias se tiene:
route_distance <- dist(route[ ,c("Longitude","Latitude")],
upper = T,
diag = T) %>%
as.matrix()
# Calcular mejor ruta:
best_route <- list(total_distance = Inf)
for (i in 1:10^4) {
try_route <- giant_path(demand = route$demand,
distance = route_distance)
if (best_route$total_distance > try_route$total_distance) {
best_route <- try_route
}
}
Las rutas están condicionadas a la capacidad y la demanda. Se divide la población entre 10 y se multiplica la capacidad por 6 (factor de escala). La configuración produce 5 rutas al igual que en todos los otros países.
nearest_result <- assign_vehicle(x = best_route$route,
demand = route$demand/10,
capacity = 30000*6,
distance = route_distance)
# Listado de nodos de las rutas identificadas
nearest_result
## $distance
## [1] 107.2878
##
## $route
## [1] 1 14 15 4 7 16 1 11 12 13 8 1 2 1 3 5 6 1 10 9 1
##
## $num_vehicle
## [1] 5
El mapa vectorial de rutas se tiene:
nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
rename(from_x1 = Longitude,
from_x2 = Latitude) %>%
left_join(route,
by = c("to" = "node")) %>%
rename(to_x1 = Longitude,
to_x2 = Latitude) %>%
rename(demand = demand.y) %>%
select(-demand.x) %>%
mutate(unit = c( rep("A", 4), # linea modificada para coincidir nodos
rep("B",7), # linea modificada para coincidir nodos
rep("C", 2), # linea modificada para coincidir nodos
rep("D", 3), # linea modificada para coincidir nodos
rep("E",4))) %>% # linea modificada para coincidir nodos
ggplot() +
geom_point(data = route,
aes(Longitude,
Latitude),
show.legend = F) +
geom_curve(aes(x = from_x1,
xend = to_x1,
y = from_x2,
yend = to_x2,
color = unit),
curvature = -0.05,
size = 0.3,
alpha = 0.6,
arrow = arrow(type = "closed",
angle = 30,
length = unit(3, "mm")) ) +
geom_point(data = route[1,],
aes(Longitude,
Latitude),
color = "red",
size = 2) +
geom_label_repel(data = route,
aes(Longitude,
Latitude,
label = node),
alpha = 0.6,
max.overlaps = Inf,
size=1) +
scale_color_manual(values = c("firebrick",
"orange",
"dodgerblue",
"green3",
"purple"))+
theme_minimal() +
theme(panel.grid = element_blank()) +
theme(legend.position = "top") +
labs(x = quote(x[1]),
y = quote(x[2]),
title = "Problema de ruta del vehículo con el vecino más cercano",
subtitle = "Capacidad del vehículo = 30000",
color = "Ruta")
La tabla con las rutas se muestra a continuación:
df<-nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
mutate(unit = c( rep("A", 4), # linea modificada para coincidir nodos
rep("B",7), # linea modificada para coincidir nodos
rep("C", 2), # linea modificada para coincidir nodos
rep("D", 3), # linea modificada para coincidir nodos
rep("E",4))) # linea modificada para coincidir nodos
dfA<-df %>% filter(unit == "A")
tripA <- osrmTrip(dfA[,c("Longitude","Latitude")],
overview = "full")
dfB<-df %>% filter(unit == "B")
tripB <- osrmTrip(dfB[,c("Longitude","Latitude")],
overview = "full")
dfC<-df %>% filter(unit == "C")
tripC <- osrmTrip(dfC[,c("Longitude","Latitude")],
overview = "full")
dfD<-df %>% filter(unit == "D")
tripD <- osrmTrip(dfD[,c("Longitude","Latitude")],
overview = "full")
dfE<-df %>% filter(unit == "E")
tripE <- osrmTrip(dfE[,c("Longitude","Latitude")],
overview = "full")
##Crear matriz para resumen:
summary = matrix(c(as.numeric(tripA[[1]]$summary),
as.numeric(tripB[[1]]$summary),
as.numeric(tripC[[1]]$summary),
as.numeric(tripD[[1]]$summary),
as.numeric(tripE[[1]]$summary)),
ncol = 2,
nrow = 5,
byrow = T)
summary[,1] = summary[,1]/60
summary = round(summary,1)
colnames(summary) = c("Duracion (h)","Distancia (km)")
rownames(summary) = c("Trip A","Trip B","Trip C","Trip D","Trip E")
#library(DT)
datatable(summary)
Luego, el mapa dinámico con las rutas:
#Create labels:
labels<- paste0("<strong> Customers </strong> ",
MyData$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
MyData$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
MyData$Latitude, "<br/> ",
"<strong> demand </strong> ",
MyData$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = MyData$Longitude,
lat = MyData$Latitude,
label = ~labels) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick") %>%
addPolylines(data = tripB[[1]]$trip,
label = "Trip B",
color = "orange") %>%
addPolylines(data = tripC[[1]]$trip,
label = "Trip C",
color = "dodgerblue") %>%
addPolylines(data = tripD[[1]]$trip,
label = "Trip D",
color = "red") %>%
addPolylines(data = tripE[[1]]$trip,
label = "Trip E",
color = "purple")
Una única ruta con marcadores:
labels2<- paste0("<strong> Customers </strong> ",
dfA$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
dfA$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
dfA$Latitude, "<br/> ",
"<strong> demand </strong> ",
dfA$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = dfA$Longitude,
lat = dfA$Latitude,
label = ~labels2) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick")
En Perú se reparte desde el Callao, cercano a la ciudad de Lima.
MyData = p_pe
new_manufacturer <- data.frame(Lat = -12.055,
Long = -77.135) # Callao
## Crear un dataframe (route) que incluya este punto y unirlo con los datos de Mydata:
route <- data.frame("Manufacturer",
new_manufacturer[,c("Long","Lat")],
0)
colnames(route) <- c("Customers",
"Longitude",
"Latitude",
"demand")
route <- rbind(route,
MyData%>% select(Customers,
Longitude,
Latitude,
demand))
## Crear un índice con el id de los nodos a procesar:
route$node <- 1:nrow(route)
La matriz de distancias queda:
route_distance <- dist(route[ ,c("Longitude","Latitude")],
upper = T,
diag = T) %>%
as.matrix()
# Calcular mejor ruta:
best_route <- list(total_distance = Inf)
for (i in 1:10^4) {
try_route <- giant_path(demand = route$demand,
distance = route_distance)
if (best_route$total_distance > try_route$total_distance) {
best_route <- try_route
}
}
La rutas están definidas por la demanda y la capacidad de los camiones. Se asume dividir entre 10 la población para definir la demanda y aplicar un factor de escala a la capacidad de los camiones de 12 veces la capacidad del transporte en Uruguay. Esta configuración produce 5 rutas.
nearest_result <- assign_vehicle(x = best_route$route,
demand = route$demand/10,
capacity = 30000*12,
distance = route_distance)
# Listado de nodos de las rutas identificadas
nearest_result
## $distance
## [1] 58.17699
##
## $route
## [1] 1 3 16 10 11 1 7 15 9 14 13 12 8 1 2 1 6 4 1 5 1
##
## $num_vehicle
## [1] 5
El mapa vectorial de rutas:
nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
rename(from_x1 = Longitude,
from_x2 = Latitude) %>%
left_join(route,
by = c("to" = "node")) %>%
rename(to_x1 = Longitude,
to_x2 = Latitude) %>%
rename(demand = demand.y) %>%
select(-demand.x) %>%
mutate(unit = c( rep("A", 5), # linea modificada para coincidir nodos
rep("B",8), # linea modificada para coincidir nodos
rep("C", 2), # linea modificada para coincidir nodos
rep("D", 3), # linea modificada para coincidir nodos
rep("E",2))) %>% # linea modificada para coincidir nodos
ggplot() +
geom_point(data = route,
aes(Longitude,
Latitude),
show.legend = F) +
geom_curve(aes(x = from_x1,
xend = to_x1,
y = from_x2,
yend = to_x2,
color = unit),
curvature = -0.05,
size = 0.3,
alpha = 0.6,
arrow = arrow(type = "closed",
angle = 30,
length = unit(3, "mm")) ) +
geom_point(data = route[1,],
aes(Longitude,
Latitude),
color = "red",
size = 2) +
geom_label_repel(data = route,
aes(Longitude,
Latitude,
label = node),
alpha = 0.6,
max.overlaps = Inf,
size=1) +
scale_color_manual(values = c("firebrick",
"orange",
"dodgerblue",
"green3",
"purple"))+
theme_minimal() +
theme(panel.grid = element_blank()) +
theme(legend.position = "top") +
labs(x = quote(x[1]),
y = quote(x[2]),
title = "Problema de ruta del vehículo con el vecino más cercano",
subtitle = "Capacidad del vehículo = 30000",
color = "Ruta")
La tabla con las distancias y tiempos:
df<-nearest_result$route %>%
as.data.frame() %>%
rename(from = ".") %>%
mutate(to = lead(from)) %>%
slice(- nrow(.)) %>%
left_join(route,
by = c("from" = "node")) %>%
mutate(unit = c( rep("A", 5), # linea modificada para coincidir nodos
rep("B",8), # linea modificada para coincidir nodos
rep("C", 2), # linea modificada para coincidir nodos
rep("D", 3), # linea modificada para coincidir nodos
rep("E",2))) # linea modificada para coincidir nodos
dfA<-df %>% filter(unit == "A")
tripA <- osrmTrip(dfA[,c("Longitude","Latitude")],
overview = "full")
dfB<-df %>% filter(unit == "B")
tripB <- osrmTrip(dfB[,c("Longitude","Latitude")],
overview = "full")
dfC<-df %>% filter(unit == "C")
tripC <- osrmTrip(dfC[,c("Longitude","Latitude")],
overview = "full")
dfD<-df %>% filter(unit == "D")
tripD <- osrmTrip(dfD[,c("Longitude","Latitude")],
overview = "full")
dfE<-df %>% filter(unit == "E")
tripE <- osrmTrip(dfE[,c("Longitude","Latitude")],
overview = "full")
##Crear matriz para resumen:
summary = matrix(c(as.numeric(tripA[[1]]$summary),
as.numeric(tripB[[1]]$summary),
as.numeric(tripC[[1]]$summary),
as.numeric(tripD[[1]]$summary),
as.numeric(tripE[[1]]$summary)),
ncol = 2,
nrow = 5,
byrow = T)
summary[,1] = summary[,1]/60
summary = round(summary,1)
colnames(summary) = c("Duracion (h)","Distancia (km)")
rownames(summary) = c("Trip A","Trip B","Trip C","Trip D","Trip E")
#library(DT)
datatable(summary)
El mapa dinámico con las rutas queda
#Create labels:
labels<- paste0("<strong> Customers </strong> ",
MyData$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
MyData$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
MyData$Latitude, "<br/> ",
"<strong> demand </strong> ",
MyData$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = MyData$Longitude,
lat = MyData$Latitude,
label = ~labels) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick") %>%
addPolylines(data = tripB[[1]]$trip,
label = "Trip B",
color = "orange") %>%
addPolylines(data = tripC[[1]]$trip,
label = "Trip C",
color = "dodgerblue") %>%
addPolylines(data = tripD[[1]]$trip,
label = "Trip D",
color = "red") %>%
addPolylines(data = tripE[[1]]$trip,
label = "Trip E",
color = "purple")
Luego, sepuede graficar una única ruta con los marcadores
labels2<- paste0("<strong> Customers </strong> ",
dfA$Customers, "<br/> ",
"<strong> Longitude: </strong> ",
dfA$Longitude, "<br/> ",
"<strong> Latitude: </strong> ",
dfA$Latitude, "<br/> ",
"<strong> demand </strong> ",
dfA$demand, "<br/> ") %>%
lapply(htmltools::HTML)
leaflet(data = MyData) %>%
addTiles() %>%
addMarkers(lng = dfA$Longitude,
lat = dfA$Latitude,
label = ~labels2) %>%
addPolylines(data = tripA[[1]]$trip,
label = "Trip A",
color = "firebrick")