FT: Mejora del modelo añadiendo control de tráfico además de demanda

This commit is contained in:
2026-01-06 21:18:00 +01:00
parent 355fe4092f
commit 7eae70a59e
2 changed files with 63 additions and 13 deletions

View File

@@ -166,6 +166,7 @@ def recommend_gruas():
- dow: día de la semana (0-6, requerido)
- hour: hora del día (0-23, requerido)
- k: número de grúas (opcional, default=2)
- traffic: nivel de tráfico 1=bajo, 2=medio, 3=alto (opcional, default=1)
- optimize: si es True, encuentra k óptimo (opcional, default=False)
- min_gruas: mínimo de grúas para optimización (opcional, default=1)
- max_gruas: máximo de grúas para optimización (opcional, default=10)
@@ -178,6 +179,7 @@ def recommend_gruas():
hour = int(request.args["hour"])
k = request.args.get("k", default=2, type=int)
traffic = request.args.get("traffic", default=1, type=int)
optimize = request.args.get("optimize", default="false").lower() == "true"
min_gruas = request.args.get("min_gruas", default=1, type=int)
max_gruas = request.args.get("max_gruas", default=10, type=int)
@@ -190,6 +192,8 @@ def recommend_gruas():
return jsonify({"error": "hour debe estar entre 0 y 23"}), 400
if k < 1:
return jsonify({"error": "k debe ser al menos 1"}), 400
if not (1 <= traffic <= 3):
return jsonify({"error": "traffic debe estar entre 1 (bajo) y 3 (alto)"}), 400
# Obtener modelos
demand_model = model_manager.get_model("demand")
@@ -201,10 +205,10 @@ def recommend_gruas():
}), 500
if DEBUG_MODE:
print(f"DEBUG: Building prediction grid for week={week}, dow={dow}, hour={hour}")
print(f"DEBUG: Building prediction grid for week={week}, dow={dow}, hour={hour}, traffic={traffic}")
# Construir grilla de predicciones
df = build_prediction_grid(week, dow, hour, demand_model, nulo_model)
df = build_prediction_grid(week, dow, hour, demand_model, nulo_model, traffic_level=traffic)
if df.empty:
return jsonify({
@@ -234,6 +238,10 @@ def recommend_gruas():
"semana": week,
"dia_semana": dow,
"hora": hour,
"trafico": {
"nivel": traffic,
"descripcion": {1: "bajo", 2: "medio", 3: "alto"}.get(traffic, "desconocido")
},
"optimizacion": {
"k_optimo": result['optimal_k'],
"porcentaje_cobertura": result['coverage_percentage'],
@@ -263,7 +271,11 @@ def recommend_gruas():
"hora": hour,
"parametros": {
"k": k,
"optimizacion": optimize
"optimizacion": optimize,
"trafico": {
"nivel": traffic,
"descripcion": {1: "bajo", 2: "medio", 3: "alto"}.get(traffic, "desconocido")
}
},
"h3_recomendados": result['selected'],
"estadisticas": result.get('statistics', []),
@@ -505,7 +517,7 @@ def index():
"ruta": "/recommend",
"metodo": "GET",
"descripcion": "Recomendar ubicaciones para grúas",
"parametros": "week, dow, hour (requeridos), k, optimize, min_gruas, max_gruas, target_coverage (opcionales)"
"parametros": "week, dow, hour (requeridos), k, traffic (1-3), optimize, min_gruas, max_gruas, target_coverage (opcionales)"
},
{
"ruta": "/coverage/radius",

View File

@@ -3,22 +3,58 @@ import pandas as pd
from typing import List, Set, Dict, Tuple
import numpy as np
def coverage_radius(expected_demand: float) -> int:
def get_max_radius_by_traffic(traffic_level: int) -> int:
"""
Determina el radio de cobertura según la demanda esperada, como medimos anteriormente
Determina el radio máximo de cobertura según el nivel de tráfico.
Nivel demanda | Radio H3
Nivel tráfico | Radio H3 máximo
---------------|----------------
Bajo (1) | 18
Medio (2) | 12
Alto (3) | 9
Args:
traffic_level: Nivel de tráfico (1=bajo, 2=medio, 3=alto)
Returns:
Radio máximo en hexágonos H3
"""
traffic_limits = {
1: 18, # Tráfico bajo
2: 12, # Tráfico medio
3: 9 # Tráfico alto
}
return traffic_limits.get(traffic_level, 18) # Default a tráfico bajo
def coverage_radius(expected_demand: float, traffic_level: int = 1) -> int:
"""
Determina el radio de cobertura según la demanda esperada y el nivel de tráfico.
El radio final es el mínimo entre el radio calculado por demanda y el límite de tráfico.
Nivel demanda | Radio H3 base
---------------|----------
baja (<2) | 18
media (2-5) | 12
alta (≥5) | 6
Args:
expected_demand: Demanda esperada
traffic_level: Nivel de tráfico (1=bajo, 2=medio, 3=alto)
Returns:
Radio de cobertura ajustado por tráfico
"""
# Radio base según demanda
if expected_demand < 2:
return 18
base_radius = 18
elif expected_demand < 5:
return 12
base_radius = 12
else:
return 6
base_radius = 6
# Aplicar restricción de tráfico
max_radius = get_max_radius_by_traffic(traffic_level)
return min(base_radius, max_radius)
def get_coverage_weight(expected_demand: float) -> float:
"""
@@ -82,12 +118,14 @@ def calculate_coverage_score(cell: str, radius: int, df: pd.DataFrame) -> float:
return total_risk * (1 + 0.1 * demand_weight)
def build_prediction_grid(week: int, dow: int, hour: int,
demand_model, nulo_model, h3_resolution: int = 8) -> pd.DataFrame:
demand_model, nulo_model, h3_resolution: int = 8,
traffic_level: int = 1) -> pd.DataFrame:
"""
Construye una cuadricula de predicciones para todas las celdas H3.
Args:
h3_resolution: Resolución H3 (default=8 para áreas urbanas)
traffic_level: Nivel de tráfico (1=bajo, 2=medio, 3=alto)
"""
# Obtener todas las celdas H3 únicas de la base de datos
from db import get_all_h3_cells
@@ -117,8 +155,8 @@ def build_prediction_grid(week: int, dow: int, hour: int,
# Calcular riesgo
risk = calculate_risk(expected_demand, nulo_prob)
# Determinar radio de cobertura y peso
radius = coverage_radius(expected_demand)
# Determinar radio de cobertura y peso (ajustado por tráfico)
radius = coverage_radius(expected_demand, traffic_level)
coverage_weight = get_coverage_weight(expected_demand)
predictions.append({