Al finalizar este laboratorio, usted será capaz de:
📚 Contexto Industrial: Trabajaremos con datos reales de control de calidad de una planta química que produce ácidos, bases, fertilizantes y polímeros. Aprenderemos a automatizar procesos de validación que en la industria deben ejecutarse cientos de veces al día.
En la industria química, los procesos de control de calidad involucran la repetición sistemática de verificaciones. Imaginen una planta que produce 150 lotes diarios de diferentes productos químicos. Cada lote debe:
Las sentencias iterativas nos permiten automatizar estos procesos repetitivos, convirtiendo horas de trabajo manual en segundos de procesamiento automatizado.
“En la industria química moderna, la diferencia entre el éxito y el fracaso a menudo radica en la capacidad de procesar información rápidamente y tomar decisiones basadas en datos en tiempo real”
# Crear dataset de control de calidad (simulación de datos industriales reales)
n_lotes <- 150
# Generar datos realistas
datos_control <- data.frame(
lote_id = sprintf("LOTE_%03d", 1:n_lotes),
fecha_produccion = seq(as.Date("2025-01-02"), as.Date("2025-03-30"), length.out = n_lotes),
turno = sample(c("Mañana", "Tarde", "Noche"), n_lotes, replace = TRUE, prob = c(0.4, 0.35, 0.25)),
producto_tipo = sample(c("Acido_Sulfurico", "Acido_Nitrico", "Soda_Caustica",
"Fertilizante_NPK", "Polimero_PVC"),
n_lotes, replace = TRUE, prob = c(0.25, 0.2, 0.2, 0.2, 0.15)),
operador_id = sprintf("OP_%03d", sample(1:25, n_lotes, replace = TRUE)),
stringsAsFactors = FALSE
)
# Generar variables químicas específicas por tipo de producto
for (i in 1:n_lotes) {
tipo <- datos_control$producto_tipo[i]
# pH según tipo de producto
if (tipo == "Acido_Sulfurico") {
datos_control$ph_inicial[i] <- runif(1, 0.5, 1.5)
datos_control$ph_final[i] <- runif(1, 0.8, 1.8)
} else if (tipo == "Acido_Nitrico") {
datos_control$ph_inicial[i] <- runif(1, 1.0, 2.0)
datos_control$ph_final[i] <- runif(1, 1.2, 2.2)
} else if (tipo == "Soda_Caustica") {
datos_control$ph_inicial[i] <- runif(1, 12.5, 13.5)
datos_control$ph_final[i] <- runif(1, 12.8, 13.8)
} else if (tipo == "Fertilizante_NPK") {
datos_control$ph_inicial[i] <- runif(1, 5.5, 7.5)
datos_control$ph_final[i] <- runif(1, 6.0, 8.0)
} else { # Polimero_PVC
datos_control$ph_inicial[i] <- runif(1, 6.5, 8.5)
datos_control$ph_final[i] <- runif(1, 7.0, 9.0)
}
# Temperatura según complejidad del proceso
if (tipo %in% c("Acido_Sulfurico", "Acido_Nitrico")) {
datos_control$temperatura_reaccion[i] <- runif(1, 65, 85)
} else if (tipo == "Polimero_PVC") {
datos_control$temperatura_reaccion[i] <- runif(1, 70, 80)
} else {
datos_control$temperatura_reaccion[i] <- runif(1, 45, 65)
}
# Presión y otras variables
datos_control$presion_bar[i] <- runif(1, 1.2, 5.8)
datos_control$concentracion_producto[i] <- runif(1, 15, 98)
datos_control$tiempo_reaccion_horas[i] <- runif(1, 0.5, 12.0)
}
# Redondear valores para realismo
datos_control$ph_inicial <- round(datos_control$ph_inicial, 2)
datos_control$ph_final <- round(datos_control$ph_final, 2)
datos_control$temperatura_reaccion <- round(datos_control$temperatura_reaccion, 1)
datos_control$presion_bar <- round(datos_control$presion_bar, 2)
datos_control$concentracion_producto <- round(datos_control$concentracion_producto, 1)
datos_control$tiempo_reaccion_horas <- round(datos_control$tiempo_reaccion_horas, 2)
# Determinar si pasa control de calidad (lógica realista)
datos_control$control_calidad_pasa <- rep(TRUE, n_lotes)
# Simular algunos fallos de control de calidad
set.seed(456)
fallos_aleatorios <- sample(1:n_lotes, 12)
datos_control$control_calidad_pasa[fallos_aleatorios] <- FALSE
cat("=== DATASET DE CONTROL DE CALIDAD CARGADO ===\n")
#> === DATASET DE CONTROL DE CALIDAD CARGADO ===
#> Dimensiones: 150 lotes × 12 variables
cat("Período:", min(datos_control$fecha_produccion), "a", max(datos_control$fecha_produccion), "\n")
#> Período: 20090 a 20177
#> Productos: Acido_Nitrico, Fertilizante_NPK, Soda_Caustica, Acido_Sulfurico, Polimero_PVC
#> Operadores únicos: 25
#> === ESTRUCTURA DEL DATASET ===
#> 'data.frame': 150 obs. of 12 variables:
#> $ lote_id : chr "LOTE_001" "LOTE_002" "LOTE_003" "LOTE_004" ...
#> $ fecha_produccion : Date, format: "2025-01-02" "2025-01-02" ...
#> $ turno : chr "Mañana" "Noche" "Tarde" "Noche" ...
#> $ producto_tipo : chr "Acido_Nitrico" "Fertilizante_NPK" "Soda_Caustica" "Acido_Sulfurico" ...
#> $ operador_id : chr "OP_010" "OP_017" "OP_017" "OP_021" ...
#> $ ph_inicial : num 1.69 6.23 12.96 0.95 0.81 ...
#> $ ph_final : num 1.99 6.36 12.88 1.57 0.84 ...
#> $ temperatura_reaccion : num 72.1 55.7 62.2 66.3 75.4 63.8 52 81.6 61 75.6 ...
#> $ presion_bar : num 2.89 3.52 3.02 4.95 4.32 4.36 5.01 2.47 2.97 3.9 ...
#> $ concentracion_producto: num 38.8 93.4 76.1 40 90 52.1 59.4 77.5 42.2 70.3 ...
#> $ tiempo_reaccion_horas : num 1.42 4.43 2.48 4.69 0.79 ...
#> $ control_calidad_pasa : logi TRUE TRUE TRUE TRUE TRUE TRUE ...
#>
#> === PRIMERAS 8 FILAS ===
#>
#> === RESUMEN ESTADÍSTICO ===
summary(datos_control[, c("ph_inicial", "ph_final", "temperatura_reaccion",
"presion_bar", "concentracion_producto")])
#> ph_inicial ph_final temperatura_reaccion presion_bar
#> Min. : 0.500 Min. : 0.800 Min. :45.10 Min. :1.220
#> 1st Qu.: 1.278 1st Qu.: 1.593 1st Qu.:56.33 1st Qu.:2.143
#> Median : 6.215 Median : 7.040 Median :67.25 Median :3.400
#> Mean : 6.017 Mean : 6.434 Mean :66.04 Mean :3.331
#> 3rd Qu.: 8.220 3rd Qu.: 8.880 3rd Qu.:75.55 3rd Qu.:4.350
#> Max. :13.490 Max. :13.790 Max. :83.80 Max. :5.670
#> concentracion_producto
#> Min. :15.20
#> 1st Qu.:39.85
#> Median :60.60
#> Mean :59.85
#> 3rd Qu.:79.78
#> Max. :97.60
#>
#> === DISTRIBUCIÓN POR TURNO ===
#>
#> Mañana Noche Tarde
#> 58 39 53
#>
#> === DISTRIBUCIÓN POR TIPO DE PRODUCTO ===
#>
#> Acido_Nitrico Acido_Sulfurico Fertilizante_NPK Polimero_PVC
#> 27 34 32 21
#> Soda_Caustica
#> 36
#>
#> === ESTADO GENERAL DE CONTROL DE CALIDAD ===
tabla_control <- table(datos_control$control_calidad_pasa)
prop_control <- prop.table(tabla_control) * 100
cat("Pasa control:", tabla_control["TRUE"], "(", round(prop_control["TRUE"], 1), "%)\n")
#> Pasa control: 138 ( 92 %)
#> Falla control: 12 ( 8 %)
Concepto Clave: Los bucles for son ideales cuando conocemos exactamente cuántas iteraciones necesitamos realizar. En análisis de datos químicos, los usamos para procesar cada grupo de datos (por producto, por operador, por turno) de manera sistemática.
# Obtener tipos únicos de productos
tipos_productos <- unique(datos_control$producto_tipo)
n_tipos <- length(tipos_productos)
cat("=== ANÁLISIS AUTOMATIZADO POR TIPO DE PRODUCTO ===\n")
#> === ANÁLISIS AUTOMATIZADO POR TIPO DE PRODUCTO ===
#> Procesando 5 tipos de productos usando bucle for...
# Crear contenedor para resultados
resultados_productos <- data.frame()
# BUCLE FOR: Analizar cada tipo de producto
for (i in 1:n_tipos) {
tipo_actual <- tipos_productos[i]
cat("Procesando:", tipo_actual, "(", i, "de", n_tipos, ")\n")
cat(paste(rep("-", nchar(tipo_actual) + 20), collapse = ""), "\n")
# Filtrar datos para este tipo
datos_tipo <- datos_control[datos_control$producto_tipo == tipo_actual, ]
n_lotes_tipo <- nrow(datos_tipo)
# Calcular estadísticas específicas
ph_promedio <- mean(datos_tipo$ph_final, na.rm = TRUE)
temp_promedio <- mean(datos_tipo$temperatura_reaccion, na.rm = TRUE)
presion_promedio <- mean(datos_tipo$presion_bar, na.rm = TRUE)
concentracion_promedio <- mean(datos_tipo$concentracion_producto, na.rm = TRUE)
# Control de calidad
lotes_exitosos <- sum(datos_tipo$control_calidad_pasa)
tasa_exito <- (lotes_exitosos / n_lotes_tipo) * 100
# Mostrar resultados
cat("Lotes procesados:", n_lotes_tipo, "\n")
cat("pH final promedio:", round(ph_promedio, 2), "\n")
cat("Temperatura promedio:", round(temp_promedio, 1), "°C\n")
cat("Presión promedio:", round(presion_promedio, 2), "bar\n")
cat("Concentración promedio:", round(concentracion_promedio, 1), "%\n")
cat("Tasa de éxito:", round(tasa_exito, 1), "%\n")
# Clasificar rendimiento
if (tasa_exito >= 95) {
rendimiento <- "Excelente"
} else if (tasa_exito >= 85) {
rendimiento <- "Bueno"
} else if (tasa_exito >= 75) {
rendimiento <- "Regular"
} else {
rendimiento <- "Deficiente"
}
cat("Clasificación:", rendimiento, "\n\n")
# Guardar en tabla resumen
fila_resultado <- data.frame(
Producto = tipo_actual,
N_Lotes = n_lotes_tipo,
pH_Promedio = round(ph_promedio, 2),
Temp_Promedio = round(temp_promedio, 1),
Presion_Promedio = round(presion_promedio, 2),
Concentracion_Promedio = round(concentracion_promedio, 1),
Tasa_Exito_Pct = round(tasa_exito, 1),
Clasificacion = rendimiento
)
resultados_productos <- rbind(resultados_productos, fila_resultado)
}
#> Procesando: Acido_Nitrico ( 1 de 5 )
#> ---------------------------------
#> Lotes procesados: 27
#> pH final promedio: 1.7
#> Temperatura promedio: 76.4 °C
#> Presión promedio: 3.45 bar
#> Concentración promedio: 65 %
#> Tasa de éxito: 85.2 %
#> Clasificación: Bueno
#>
#> Procesando: Fertilizante_NPK ( 2 de 5 )
#> ------------------------------------
#> Lotes procesados: 32
#> pH final promedio: 7.1
#> Temperatura promedio: 54.6 °C
#> Presión promedio: 3.54 bar
#> Concentración promedio: 68.1 %
#> Tasa de éxito: 87.5 %
#> Clasificación: Bueno
#>
#> Procesando: Soda_Caustica ( 3 de 5 )
#> ---------------------------------
#> Lotes procesados: 36
#> pH final promedio: 13.3
#> Temperatura promedio: 55.5 °C
#> Presión promedio: 2.97 bar
#> Concentración promedio: 57.9 %
#> Tasa de éxito: 97.2 %
#> Clasificación: Excelente
#>
#> Procesando: Acido_Sulfurico ( 4 de 5 )
#> -----------------------------------
#> Lotes procesados: 34
#> pH final promedio: 1.25
#> Temperatura promedio: 75 °C
#> Presión promedio: 3.45 bar
#> Concentración promedio: 56 %
#> Tasa de éxito: 91.2 %
#> Clasificación: Bueno
#>
#> Procesando: Polimero_PVC ( 5 de 5 )
#> --------------------------------
#> Lotes procesados: 21
#> pH final promedio: 8.12
#> Temperatura promedio: 73.9 °C
#> Presión promedio: 3.27 bar
#> Concentración promedio: 50.3 %
#> Tasa de éxito: 100 %
#> Clasificación: Excelente
#> === RESUMEN EJECUTIVO POR PRODUCTO ===
kable(resultados_productos,
caption = "Análisis Automatizado de Control de Calidad por Producto",
align = "lccccccl")
Producto | N_Lotes | pH_Promedio | Temp_Promedio | Presion_Promedio | Concentracion_Promedio | Tasa_Exito_Pct | Clasificacion |
---|---|---|---|---|---|---|---|
Acido_Nitrico | 27 | 1.70 | 76.4 | 3.45 | 65.0 | 85.2 | Bueno |
Fertilizante_NPK | 32 | 7.10 | 54.6 | 3.54 | 68.1 | 87.5 | Bueno |
Soda_Caustica | 36 | 13.30 | 55.5 | 2.97 | 57.9 | 97.2 | Excelente |
Acido_Sulfurico | 34 | 1.25 | 75.0 | 3.45 | 56.0 | 91.2 | Bueno |
Polimero_PVC | 21 | 8.12 | 73.9 | 3.27 | 50.3 | 100.0 | Excelente |
Objetivo: Implementar un bucle for para analizar el rendimiento por turno de trabajo.
Instrucciones: 1. Crear un bucle que procese cada turno (Mañana, Tarde, Noche) 2. Calcular para cada turno: número de lotes, temperatura promedio, tasa de éxito 3. Identificar qué turno tiene mejor control de calidad 4. Determinar si hay diferencias significativas entre turnos
# SOLUCIÓN: Análisis por turno usando bucle for
turnos_unicos <- unique(datos_control$turno)
cat("=== ANÁLISIS POR TURNO DE TRABAJO ===\n\n")
#> === ANÁLISIS POR TURNO DE TRABAJO ===
resultados_turnos <- data.frame()
for (turno in turnos_unicos) {
cat("Analizando turno:", turno, "\n")
# Filtrar datos del turno
datos_turno <- datos_control[datos_control$turno == turno, ]
n_lotes <- nrow(datos_turno)
# Calcular métricas
temp_media <- mean(datos_turno$temperatura_reaccion)
temp_variabilidad <- sd(datos_turno$temperatura_reaccion)
cv_temperatura <- (temp_variabilidad / temp_media) * 100
lotes_exitosos <- sum(datos_turno$control_calidad_pasa)
tasa_exito <- (lotes_exitosos / n_lotes) * 100
# Análisis de operadores únicos por turno
operadores_turno <- length(unique(datos_turno$operador_id))
cat(" Lotes procesados:", n_lotes, "\n")
cat(" Temperatura media:", round(temp_media, 1), "°C\n")
cat(" Variabilidad temperatura (CV):", round(cv_temperatura, 1), "%\n")
cat(" Tasa de éxito:", round(tasa_exito, 1), "%\n")
cat(" Operadores diferentes:", operadores_turno, "\n")
# Evaluación de consistencia
if (cv_temperatura < 10) {
consistencia <- "Alta"
} else if (cv_temperatura < 15) {
consistencia <- "Media"
} else {
consistencia <- "Baja"
}
cat(" Consistencia de temperatura:", consistencia, "\n\n")
# Guardar resultados
fila_turno <- data.frame(
Turno = turno,
N_Lotes = n_lotes,
Temp_Media = round(temp_media, 1),
CV_Temperatura = round(cv_temperatura, 1),
Tasa_Exito = round(tasa_exito, 1),
N_Operadores = operadores_turno,
Consistencia = consistencia
)
resultados_turnos <- rbind(resultados_turnos, fila_turno)
}
#> Analizando turno: Mañana
#> Lotes procesados: 58
#> Temperatura media: 67.7 °C
#> Variabilidad temperatura (CV): 16.6 %
#> Tasa de éxito: 89.7 %
#> Operadores diferentes: 22
#> Consistencia de temperatura: Baja
#>
#> Analizando turno: Noche
#> Lotes procesados: 39
#> Temperatura media: 66.6 °C
#> Variabilidad temperatura (CV): 18.2 %
#> Tasa de éxito: 94.9 %
#> Operadores diferentes: 17
#> Consistencia de temperatura: Baja
#>
#> Analizando turno: Tarde
#> Lotes procesados: 53
#> Temperatura media: 63.8 °C
#> Variabilidad temperatura (CV): 16.9 %
#> Tasa de éxito: 92.5 %
#> Operadores diferentes: 24
#> Consistencia de temperatura: Baja
# Identificar mejor turno
mejor_turno <- resultados_turnos$Turno[which.max(resultados_turnos$Tasa_Exito)]
cat("CONCLUSIÓN: El turno con mejor rendimiento es:", mejor_turno, "\n")
#> CONCLUSIÓN: El turno con mejor rendimiento es: Noche
kable(resultados_turnos,
caption = "Análisis de Rendimiento por Turno de Trabajo",
align = "lcccccc")
Turno | N_Lotes | Temp_Media | CV_Temperatura | Tasa_Exito | N_Operadores | Consistencia |
---|---|---|---|---|---|---|
Mañana | 58 | 67.7 | 16.6 | 89.7 | 22 | Baja |
Noche | 39 | 66.6 | 18.2 | 94.9 | 17 | Baja |
Tarde | 53 | 63.8 | 16.9 | 92.5 | 24 | Baja |
#> === ANÁLISIS CRUZADO: PRODUCTO × TURNO ===
#> Implementando bucles anidados para análisis bidimensional...
# Crear matriz de resultados
matriz_resultados <- data.frame()
# BUCLE EXTERNO: Por cada producto
for (producto in tipos_productos) {
# BUCLE INTERNO: Por cada turno
for (turno in turnos_unicos) {
# Filtrar datos para esta combinación específica
datos_combinacion <- datos_control[
datos_control$producto_tipo == producto &
datos_control$turno == turno,
]
n_lotes_comb <- nrow(datos_combinacion)
if (n_lotes_comb > 0) { # Solo procesar si hay datos
# Calcular métricas
ph_promedio <- mean(datos_combinacion$ph_final)
temp_promedio <- mean(datos_combinacion$temperatura_reaccion)
lotes_exitosos <- sum(datos_combinacion$control_calidad_pasa)
tasa_exito <- (lotes_exitosos / n_lotes_comb) * 100
# Crear fila de resultados
fila <- data.frame(
Producto = producto,
Turno = turno,
N_Lotes = n_lotes_comb,
pH_Promedio = round(ph_promedio, 2),
Temp_Promedio = round(temp_promedio, 1),
Tasa_Exito = round(tasa_exito, 1)
)
matriz_resultados <- rbind(matriz_resultados, fila)
}
}
}
cat("Procesamiento completado. Total de combinaciones válidas:", nrow(matriz_resultados), "\n\n")
#> Procesamiento completado. Total de combinaciones válidas: 15
# Mostrar resultados ordenados por tasa de éxito
matriz_ordenada <- matriz_resultados[order(-matriz_resultados$Tasa_Exito), ]
cat("=== TOP 5 MEJORES COMBINACIONES PRODUCTO-TURNO ===\n")
#> === TOP 5 MEJORES COMBINACIONES PRODUCTO-TURNO ===
kable(head(matriz_ordenada, 5),
caption = "Mejores Combinaciones de Producto y Turno",
align = "llccccc")
Producto | Turno | N_Lotes | pH_Promedio | Temp_Promedio | Tasa_Exito | |
---|---|---|---|---|---|---|
5 | Fertilizante_NPK | Noche | 6 | 6.67 | 55.6 | 100 |
7 | Soda_Caustica | Mañana | 11 | 13.22 | 56.1 | 100 |
8 | Soda_Caustica | Noche | 11 | 13.42 | 53.8 | 100 |
12 | Acido_Sulfurico | Tarde | 7 | 1.42 | 75.1 | 100 |
13 | Polimero_PVC | Mañana | 12 | 8.14 | 73.9 | 100 |
#>
#> === IDENTIFICACIÓN DE PATRONES ===
mejor_combinacion <- matriz_ordenada[1, ]
cat("Mejor combinación:", mejor_combinacion$Producto, "en turno", mejor_combinacion$Turno,
"con", mejor_combinacion$Tasa_Exito, "% de éxito\n")
#> Mejor combinación: Fertilizante_NPK en turno Noche con 100 % de éxito
peor_combinacion <- matriz_ordenada[nrow(matriz_ordenada), ]
cat("Combinación a mejorar:", peor_combinacion$Producto, "en turno", peor_combinacion$Turno,
"con", peor_combinacion$Tasa_Exito, "% de éxito\n")
#> Combinación a mejorar: Acido_Nitrico en turno Mañana con 80 % de éxito
Concepto Clave: Los bucles while se ejecutan mientras una condición sea verdadera. Son ideales para procesos de validación iterativa, detección de anomalías, y refinamiento progresivo de datos químicos donde no sabemos cuántas iteraciones necesitaremos.
# BUCLE WHILE: Refinamiento iterativo de criterios de calidad
cat("=== SISTEMA DE CONTROL DE CALIDAD ITERATIVO ===\n")
#> === SISTEMA DE CONTROL DE CALIDAD ITERATIVO ===
#> Objetivo: Ajustar criterios hasta alcanzar 90% de lotes aprobados
# Parámetros iniciales
datos_trabajo <- datos_control
criterio_ph_min <- 1.0
criterio_ph_max <- 13.0
criterio_temp_max <- 90.0
iteracion <- 0
max_iteraciones <- 10
objetivo_aprobacion <- 0.90 # 90% de lotes deben pasar
# Función para aplicar criterios de calidad
aplicar_criterios <- function(datos, ph_min, ph_max, temp_max) {
cumple_ph <- datos$ph_final >= ph_min & datos$ph_final <= ph_max
cumple_temp <- datos$temperatura_reaccion <= temp_max
cumple_presion <- datos$presion_bar >= 1.0 & datos$presion_bar <= 6.0
return(cumple_ph & cumple_temp & cumple_presion)
}
# BUCLE WHILE: Ajustar criterios iterativamente
tasa_aprobacion_actual <- 0
while (tasa_aprobacion_actual < objetivo_aprobacion && iteracion < max_iteraciones) {
iteracion <- iteracion + 1
cat("Iteración", iteracion, ":\n")
# Aplicar criterios actuales
lotes_aprueban <- aplicar_criterios(datos_trabajo, criterio_ph_min,
criterio_ph_max, criterio_temp_max)
n_aprobados <- sum(lotes_aprueban)
tasa_aprobacion_actual <- n_aprobados / nrow(datos_trabajo)
cat(" Criterios: pH [", criterio_ph_min, ",", criterio_ph_max,
"], Temp ≤", criterio_temp_max, "°C\n")
cat(" Lotes aprobados:", n_aprobados, "de", nrow(datos_trabajo),
"(", round(tasa_aprobacion_actual * 100, 1), "%)\n")
if (tasa_aprobacion_actual < objetivo_aprobacion) {
# Relajar criterios gradualmente
if (iteracion %% 2 == 1) {
# Iteraciones impares: ajustar pH
criterio_ph_min <- max(0.5, criterio_ph_min - 0.2)
criterio_ph_max <- min(14.0, criterio_ph_max + 0.2)
cat(" Acción: Relajar criterios de pH\n")
} else {
# Iteraciones pares: ajustar temperatura
criterio_temp_max <- min(100.0, criterio_temp_max + 2.0)
cat(" Acción: Aumentar límite de temperatura\n")
}
}
cat("\n")
}
#> Iteración 1 :
#> Criterios: pH [ 1 , 13 ], Temp ≤ 90 °C
#> Lotes aprobados: 111 de 150 ( 74 %)
#> Acción: Relajar criterios de pH
#>
#> Iteración 2 :
#> Criterios: pH [ 0.8 , 13.2 ], Temp ≤ 90 °C
#> Lotes aprobados: 129 de 150 ( 86 %)
#> Acción: Aumentar límite de temperatura
#>
#> Iteración 3 :
#> Criterios: pH [ 0.8 , 13.2 ], Temp ≤ 92 °C
#> Lotes aprobados: 129 de 150 ( 86 %)
#> Acción: Relajar criterios de pH
#>
#> Iteración 4 :
#> Criterios: pH [ 0.6 , 13.4 ], Temp ≤ 92 °C
#> Lotes aprobados: 137 de 150 ( 91.3 %)
# Resultado final
if (tasa_aprobacion_actual >= objetivo_aprobacion) {
cat("ÉXITO: Criterios optimizados en", iteracion, "iteraciones\n")
cat("Tasa final de aprobación:", round(tasa_aprobacion_actual * 100, 1), "%\n")
} else {
cat("ADVERTENCIA: No se alcanzó el objetivo en", max_iteraciones, "iteraciones\n")
cat("Tasa máxima alcanzada:", round(tasa_aprobacion_actual * 100, 1), "%\n")
}
#> ÉXITO: Criterios optimizados en 4 iteraciones
#> Tasa final de aprobación: 91.3 %
#> Criterios finales optimizados:
#> - pH: 0.6 a 13.4
#> - Temperatura: ≤ 92 °C
#> - Presión: 1.0 a 6.0 bar
# BUCLE WHILE: Identificar lotes con múltiples problemas
cat("=== DETECCIÓN ITERATIVA DE LOTES PROBLEMÁTICOS ===\n")
#> === DETECCIÓN ITERATIVA DE LOTES PROBLEMÁTICOS ===
#> Buscando lotes que requieren atención especial...
# Crear copia de datos para análisis
datos_analisis <- datos_control
lotes_problematicos <- character(0)
rondas_analisis <- 0
max_rondas <- 5
# Criterios de problema (se van refinando)
tolerancia_ph <- 0.5
tolerancia_temp <- 5.0
min_concentracion <- 20.0
continuar_analisis <- TRUE
while (continuar_analisis && rondas_analisis < max_rondas) {
rondas_analisis <- rondas_analisis + 1
cat("Ronda de análisis", rondas_analisis, ":\n")
cat("Tolerancias actuales: pH ±", tolerancia_ph,
", Temp ±", tolerancia_temp, "°C, Conc ≥", min_concentracion, "%\n")
problemas_encontrados <- 0
# Buscar problemas específicos por tipo de producto
for (i in 1:nrow(datos_analisis)) {
lote <- datos_analisis[i, ]
tipo <- lote$producto_tipo
problemas_lote <- character(0)
# Verificar pH según tipo
if (tipo == "Acido_Sulfurico" && (lote$ph_final < 0.5 || lote$ph_final > 2.0)) {
problemas_lote <- c(problemas_lote, "pH_fuera_rango")
}
if (tipo == "Soda_Caustica" && (lote$ph_final < 12.0 || lote$ph_final > 14.0)) {
problemas_lote <- c(problemas_lote, "pH_fuera_rango")
}
# Verificar temperatura
if (abs(lote$temperatura_reaccion - mean(datos_analisis$temperatura_reaccion)) > tolerancia_temp) {
problemas_lote <- c(problemas_lote, "temperatura_atipica")
}
# Verificar concentración
if (lote$concentracion_producto < min_concentracion) {
problemas_lote <- c(problemas_lote, "concentracion_baja")
}
# Si tiene múltiples problemas, marcarlo
if (length(problemas_lote) >= 2 && !lote$lote_id %in% lotes_problematicos) {
lotes_problematicos <- c(lotes_problematicos, lote$lote_id)
problemas_encontrados <- problemas_encontrados + 1
cat(" PROBLEMA DETECTADO:", lote$lote_id, "-", paste(problemas_lote, collapse = ", "), "\n")
}
}
cat(" Nuevos lotes problemáticos encontrados:", problemas_encontrados, "\n")
cat(" Total acumulado de lotes problemáticos:", length(lotes_problematicos), "\n\n")
# Decidir si continuar
if (problemas_encontrados == 0) {
continuar_analisis <- FALSE
cat("No se encontraron nuevos problemas. Análisis completado.\n")
} else {
# Hacer criterios más estrictos para la próxima ronda
tolerancia_ph <- tolerancia_ph * 0.8
tolerancia_temp <- tolerancia_temp * 0.9
min_concentracion <- min_concentracion + 2.0
}
}
#> Ronda de análisis 1 :
#> Tolerancias actuales: pH ± 0.5 , Temp ± 5 °C, Conc ≥ 20 %
#> PROBLEMA DETECTADO: LOTE_029 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_067 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_069 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_134 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_147 - temperatura_atipica, concentracion_baja
#> Nuevos lotes problemáticos encontrados: 5
#> Total acumulado de lotes problemáticos: 5
#>
#> Ronda de análisis 2 :
#> Tolerancias actuales: pH ± 0.4 , Temp ± 4.5 °C, Conc ≥ 22 %
#> PROBLEMA DETECTADO: LOTE_110 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_114 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_124 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_135 - temperatura_atipica, concentracion_baja
#> Nuevos lotes problemáticos encontrados: 4
#> Total acumulado de lotes problemáticos: 9
#>
#> Ronda de análisis 3 :
#> Tolerancias actuales: pH ± 0.32 , Temp ± 4.05 °C, Conc ≥ 24 %
#> PROBLEMA DETECTADO: LOTE_023 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_050 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_064 - temperatura_atipica, concentracion_baja
#> Nuevos lotes problemáticos encontrados: 3
#> Total acumulado de lotes problemáticos: 12
#>
#> Ronda de análisis 4 :
#> Tolerancias actuales: pH ± 0.256 , Temp ± 3.645 °C, Conc ≥ 26 %
#> PROBLEMA DETECTADO: LOTE_051 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_121 - temperatura_atipica, concentracion_baja
#> Nuevos lotes problemáticos encontrados: 2
#> Total acumulado de lotes problemáticos: 14
#>
#> Ronda de análisis 5 :
#> Tolerancias actuales: pH ± 0.2048 , Temp ± 3.2805 °C, Conc ≥ 28 %
#> PROBLEMA DETECTADO: LOTE_045 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_072 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_090 - temperatura_atipica, concentracion_baja
#> PROBLEMA DETECTADO: LOTE_112 - temperatura_atipica, concentracion_baja
#> Nuevos lotes problemáticos encontrados: 4
#> Total acumulado de lotes problemáticos: 18
#> === RESUMEN DE LOTES PROBLEMÁTICOS ===
#> Total de lotes que requieren atención: 18
cat("Porcentaje del total:", round((length(lotes_problematicos) / nrow(datos_control)) * 100, 1), "%\n")
#> Porcentaje del total: 12 %
if (length(lotes_problematicos) > 0) {
cat("Lotes identificados:", paste(head(lotes_problematicos, 10), collapse = ", "))
if (length(lotes_problematicos) > 10) {
cat(", ... y", length(lotes_problematicos) - 10, "más")
}
cat("\n")
}
#> Lotes identificados: LOTE_029, LOTE_067, LOTE_069, LOTE_134, LOTE_147, LOTE_110, LOTE_114, LOTE_124, LOTE_135, LOTE_023, ... y 8 más
Escenario: La planta necesita optimizar el tiempo de reacción para maximizar la concentración del producto manteniendo la calidad.
Tarea: Implementar un bucle while que: 1. Comience con un tiempo mínimo de reacción 2. Incremente gradualmente el tiempo hasta encontrar el óptimo 3. El óptimo es cuando se maximiza concentración × tasa_éxito 4. Se detenga cuando no haya mejora en 3 iteraciones consecutivas
#> === OPTIMIZACIÓN DE TIEMPO DE REACCIÓN ===
# Parámetros iniciales
tiempo_actual <- 1.0 # horas
mejor_score <- 0
mejor_tiempo <- tiempo_actual
iteraciones_sin_mejora <- 0
max_sin_mejora <- 3
iteracion_opt <- 0
cat("Buscando tiempo óptimo de reacción...\n\n")
#> Buscando tiempo óptimo de reacción...
while (iteraciones_sin_mejora < max_sin_mejora && tiempo_actual <= 10.0) {
iteracion_opt <- iteracion_opt + 1
# Filtrar lotes con tiempo similar al actual (±0.5 horas)
lotes_similares <- datos_control[
abs(datos_control$tiempo_reaccion_horas - tiempo_actual) <= 0.5,
]
if (nrow(lotes_similares) >= 5) { # Necesitamos muestra mínima
# Calcular métricas
concentracion_media <- mean(lotes_similares$concentracion_producto)
tasa_exito <- mean(lotes_similares$control_calidad_pasa)
score_actual <- concentracion_media * tasa_exito
cat("Iteración", iteracion_opt, "- Tiempo:", tiempo_actual, "horas\n")
cat(" Lotes en muestra:", nrow(lotes_similares), "\n")
cat(" Concentración media:", round(concentracion_media, 1), "%\n")
cat(" Tasa de éxito:", round(tasa_exito * 100, 1), "%\n")
cat(" Score combinado:", round(score_actual, 2), "\n")
# Verificar si es mejor
if (score_actual > mejor_score) {
mejor_score <- score_actual
mejor_tiempo <- tiempo_actual
iteraciones_sin_mejora <- 0
cat(" ¡NUEVA MEJOR SOLUCIÓN!\n")
} else {
iteraciones_sin_mejora <- iteraciones_sin_mejora + 1
cat(" Sin mejora (", iteraciones_sin_mejora, "/", max_sin_mejora, ")\n")
}
} else {
cat("Iteración", iteracion_opt, "- Tiempo:", tiempo_actual,
"horas - Muestra insuficiente (", nrow(lotes_similares), "lotes)\n")
}
cat("\n")
tiempo_actual <- tiempo_actual + 0.5
}
#> Iteración 1 - Tiempo: 1 horas
#> Lotes en muestra: 17
#> Concentración media: 62.7 %
#> Tasa de éxito: 82.4 %
#> Score combinado: 51.65
#> ¡NUEVA MEJOR SOLUCIÓN!
#>
#> Iteración 2 - Tiempo: 1.5 horas
#> Lotes en muestra: 16
#> Concentración media: 62.6 %
#> Tasa de éxito: 87.5 %
#> Score combinado: 54.76
#> ¡NUEVA MEJOR SOLUCIÓN!
#>
#> Iteración 3 - Tiempo: 2 horas
#> Lotes en muestra: 12
#> Concentración media: 72.4 %
#> Tasa de éxito: 100 %
#> Score combinado: 72.42
#> ¡NUEVA MEJOR SOLUCIÓN!
#>
#> Iteración 4 - Tiempo: 2.5 horas
#> Lotes en muestra: 13
#> Concentración media: 62.6 %
#> Tasa de éxito: 84.6 %
#> Score combinado: 53.01
#> Sin mejora ( 1 / 3 )
#>
#> Iteración 5 - Tiempo: 3 horas
#> Lotes en muestra: 15
#> Concentración media: 56.2 %
#> Tasa de éxito: 86.7 %
#> Score combinado: 48.74
#> Sin mejora ( 2 / 3 )
#>
#> Iteración 6 - Tiempo: 3.5 horas
#> Lotes en muestra: 19
#> Concentración media: 55.9 %
#> Tasa de éxito: 100 %
#> Score combinado: 55.89
#> Sin mejora ( 3 / 3 )
#> === RESULTADO DE OPTIMIZACIÓN ===
#> Tiempo óptimo encontrado: 2 horas
#> Score óptimo: 72.42
#> Proceso completado en 6 iteraciones
# Validar resultado final
lotes_optimos <- datos_control[
abs(datos_control$tiempo_reaccion_horas - mejor_tiempo) <= 0.5,
]
cat("\nValidación del resultado óptimo:\n")
#>
#> Validación del resultado óptimo:
#> - Lotes con tiempo óptimo: 12
#> - Concentración promedio: 72.4 %
#> - Tasa de éxito: 100 %
# Función para clasificar lotes automáticamente
clasificar_lote <- function(lote) {
# Inicializar clasificación
clasificacion <- "Pendiente"
problemas <- character(0)
score_calidad <- 100
# Evaluar pH según tipo de producto
if (lote$producto_tipo == "Acido_Sulfurico") {
if (lote$ph_final < 0.8 || lote$ph_final > 1.8) {
problemas <- c(problemas, "pH_inadecuado")
score_calidad <- score_calidad - 20
}
} else if (lote$producto_tipo == "Soda_Caustica") {
if (lote$ph_final < 12.5 || lote$ph_final > 13.8) {
problemas <- c(problemas, "pH_inadecuado")
score_calidad <- score_calidad - 20
}
} else if (lote$producto_tipo == "Fertilizante_NPK") {
if (lote$ph_final < 6.0 || lote$ph_final > 8.0) {
problemas <- c(problemas, "pH_inadecuado")
score_calidad <- score_calidad - 15
}
}
# Evaluar temperatura
if (lote$temperatura_reaccion < 45 || lote$temperatura_reaccion > 85) {
problemas <- c(problemas, "temperatura_extrema")
score_calidad <- score_calidad - 15
}
# Evaluar presión
if (lote$presion_bar < 1.0 || lote$presion_bar > 6.0) {
problemas <- c(problemas, "presion_fuera_rango")
score_calidad <- score_calidad - 10
}
# Evaluar concentración
if (lote$concentracion_producto < 30) {
problemas <- c(problemas, "concentracion_baja")
score_calidad <- score_calidad - 25
} else if (lote$concentracion_producto > 95) {
problemas <- c(problemas, "concentracion_excesiva")
score_calidad <- score_calidad - 10
}
# Clasificación final basada en score
if (score_calidad >= 95) {
clasificacion <- "Premium"
} else if (score_calidad >= 85) {
clasificacion <- "Estandar"
} else if (score_calidad >= 70) {
clasificacion <- "Aceptable"
} else if (score_calidad >= 50) {
clasificacion <- "Requiere_Revision"
} else {
clasificacion <- "Rechazado"
}
return(list(
clasificacion = clasificacion,
score = score_calidad,
problemas = problemas
))
}
# Aplicar clasificación a todos los lotes
cat("=== SISTEMA DE CLASIFICACIÓN AUTOMÁTICA ===\n")
#> === SISTEMA DE CLASIFICACIÓN AUTOMÁTICA ===
#> Procesando 150 lotes...
resultados_clasificacion <- data.frame()
for (i in 1:nrow(datos_control)) {
lote_actual <- datos_control[i, ]
resultado <- clasificar_lote(lote_actual)
fila_resultado <- data.frame(
Lote_ID = lote_actual$lote_id,
Producto = lote_actual$producto_tipo,
Turno = lote_actual$turno,
Clasificacion = resultado$clasificacion,
Score_Calidad = resultado$score,
N_Problemas = length(resultado$problemas),
Problemas = ifelse(length(resultado$problemas) > 0,
paste(resultado$problemas, collapse = "; "),
"Ninguno")
)
resultados_clasificacion <- rbind(resultados_clasificacion, fila_resultado)
}
# Resumen de clasificaciones
cat("=== RESUMEN DE CLASIFICACIONES ===\n")
#> === RESUMEN DE CLASIFICACIONES ===
tabla_clasificaciones <- table(resultados_clasificacion$Clasificacion)
for (i in 1:length(tabla_clasificaciones)) {
nombre_clase <- names(tabla_clasificaciones)[i]
cantidad <- tabla_clasificaciones[i]
porcentaje <- round((cantidad / nrow(datos_control)) * 100, 1)
cat(nombre_clase, ":", cantidad, "lotes (", porcentaje, "%)\n")
}
#> Aceptable : 23 lotes ( 15.3 %)
#> Estandar : 8 lotes ( 5.3 %)
#> Premium : 119 lotes ( 79.3 %)
#>
#> === LOTES PREMIUM (TOP 5) ===
lotes_premium <- resultados_clasificacion[resultados_clasificacion$Clasificacion == "Premium", ]
if (nrow(lotes_premium) > 0) {
kable(head(lotes_premium[order(-lotes_premium$Score_Calidad), ], 5),
caption = "Lotes de Calidad Premium")
} else {
cat("No hay lotes clasificados como Premium\n")
}
Lote_ID | Producto | Turno | Clasificacion | Score_Calidad | N_Problemas | Problemas |
---|---|---|---|---|---|---|
LOTE_001 | Acido_Nitrico | Mañana | Premium | 100 | 0 | Ninguno |
LOTE_002 | Fertilizante_NPK | Noche | Premium | 100 | 0 | Ninguno |
LOTE_003 | Soda_Caustica | Tarde | Premium | 100 | 0 | Ninguno |
LOTE_004 | Acido_Sulfurico | Noche | Premium | 100 | 0 | Ninguno |
LOTE_005 | Acido_Sulfurico | Noche | Premium | 100 | 0 | Ninguno |
#>
#> === LOTES PROBLEMÁTICOS ===
lotes_problematicos <- resultados_clasificacion[
resultados_clasificacion$Clasificacion %in% c("Requiere_Revision", "Rechazado"),
]
if (nrow(lotes_problematicos) > 0) {
kable(head(lotes_problematicos, 5),
caption = "Lotes que Requieren Atención")
} else {
cat("No hay lotes problemáticos\n")
}
#> No hay lotes problemáticos
Principio Clave: En R, muchas operaciones pueden hacerse de manera vectorizada (sin bucles), lo que es más eficiente. Sin embargo, los bucles son necesarios cuando la lógica es compleja o cuando cada iteración depende de las anteriores.
# Comparación de métodos para calcular estadísticas por grupo
cat("=== COMPARACIÓN: BUCLES vs VECTORIZACIÓN ===\n\n")
#> === COMPARACIÓN: BUCLES vs VECTORIZACIÓN ===
# Método 1: Con bucle for (menos eficiente)
tiempo_inicio_bucle <- Sys.time()
resultados_bucle <- data.frame()
for (producto in unique(datos_control$producto_tipo)) {
datos_producto <- datos_control[datos_control$producto_tipo == producto, ]
resultado <- data.frame(
Producto = producto,
Media_pH = mean(datos_producto$ph_final),
Media_Temp = mean(datos_producto$temperatura_reaccion),
Media_Concentracion = mean(datos_producto$concentracion_producto)
)
resultados_bucle <- rbind(resultados_bucle, resultado)
}
tiempo_fin_bucle <- Sys.time()
tiempo_bucle <- tiempo_fin_bucle - tiempo_inicio_bucle
# Método 2: Con vectorización usando dplyr (más eficiente)
tiempo_inicio_vector <- Sys.time()
resultados_vector <- datos_control %>%
group_by(producto_tipo) %>%
summarise(
Media_pH = mean(ph_final),
Media_Temp = mean(temperatura_reaccion),
Media_Concentracion = mean(concentracion_producto),
.groups = 'drop'
) %>%
rename(Producto = producto_tipo)
tiempo_fin_vector <- Sys.time()
tiempo_vector <- tiempo_fin_vector - tiempo_inicio_vector
# Mostrar resultados
cat("TIEMPOS DE EJECUCIÓN:\n")
#> TIEMPOS DE EJECUCIÓN:
cat("Método con bucle for:", round(as.numeric(tiempo_bucle, units = "secs") * 1000, 2), "milisegundos\n")
#> Método con bucle for: 8.45 milisegundos
cat("Método vectorizado:", round(as.numeric(tiempo_vector, units = "secs") * 1000, 2), "milisegundos\n")
#> Método vectorizado: 14.5 milisegundos
factor_mejora <- as.numeric(tiempo_bucle) / as.numeric(tiempo_vector)
cat("Factor de mejora:", round(factor_mejora, 1), "x más rápido\n\n")
#> Factor de mejora: 0.6 x más rápido
# Verificar que dan el mismo resultado
cat("¿Los resultados son idénticos?",
all.equal(resultados_bucle[order(resultados_bucle$Producto), ],
as.data.frame(resultados_vector[order(resultados_vector$Producto), ]),
check.attributes = FALSE), "\n\n")
#> ¿Los resultados son idénticos? TRUE
#> === RECOMENDACIONES DE USO ===
#> USAR BUCLES cuando:
#> - La lógica es compleja (múltiples condicionales)
#> - Cada iteración depende de las anteriores
#> - Necesitas control fino sobre el proceso
#> - Generas reportes con formato específico
#> USAR VECTORIZACIÓN cuando:
#> - Operaciones matemáticas simples
#> - Agrupaciones y resúmenes estadísticos
#> - Transformaciones de columnas
#> - Máximo rendimiento es prioritario
# Ejemplo donde los bucles son la mejor opción: Sistema de alertas escalonado
cat("=== SISTEMA DE ALERTAS ESCALONADO ===\n")
#> === SISTEMA DE ALERTAS ESCALONADO ===
#> Caso donde los bucles son indispensables...
# Función que requiere lógica compleja (no vectorizable fácilmente)
generar_alertas_lote <- function(lote, historial_operador) {
alertas <- character(0)
nivel_urgencia <- 0
# Alerta básica por parámetros químicos
if (lote$ph_final < 2 && lote$producto_tipo %in% c("Acido_Sulfurico", "Acido_Nitrico")) {
alertas <- c(alertas, "CRÍTICO: pH extremadamente bajo")
nivel_urgencia <- nivel_urgencia + 3
}
if (lote$temperatura_reaccion > 80) {
alertas <- c(alertas, "ADVERTENCIA: Temperatura alta")
nivel_urgencia <- nivel_urgencia + 2
}
# Alerta basada en historial del operador (requiere contexto)
fallos_operador <- sum(!historial_operador$control_calidad_pasa)
total_lotes_operador <- nrow(historial_operador)
tasa_fallo_operador <- fallos_operador / total_lotes_operador
if (tasa_fallo_operador > 0.15) { # Si el operador falla más del 15%
alertas <- c(alertas, "ATENCIÓN: Operador con alta tasa de fallos")
nivel_urgencia <- nivel_urgencia + 1
}
# Alerta por tendencia temporal (requiere análisis secuencial)
if (nrow(historial_operador) >= 3) {
ultimos_3 <- tail(historial_operador, 3)
if (sum(ultimos_3$control_calidad_pasa) <= 1) {
alertas <- c(alertas, "URGENTE: Tendencia negativa reciente")
nivel_urgencia <- nivel_urgencia + 4
}
}
# Clasificar nivel de urgencia
if (nivel_urgencia >= 5) {
prioridad <- "CRÍTICA"
} else if (nivel_urgencia >= 3) {
prioridad <- "ALTA"
} else if (nivel_urgencia >= 1) {
prioridad <- "MEDIA"
} else {
prioridad <- "NORMAL"
}
return(list(
alertas = alertas,
nivel_urgencia = nivel_urgencia,
prioridad = prioridad
))
}
# Procesar alertas (REQUIERE bucle debido a la complejidad)
cat("Generando alertas para todos los lotes...\n")
#> Generando alertas para todos los lotes...
alertas_sistema <- data.frame()
operadores_unicos <- unique(datos_control$operador_id)
for (operador in operadores_unicos) {
# Obtener historial del operador ordenado por fecha
lotes_operador <- datos_control[
datos_control$operador_id == operador,
][order(datos_control[datos_control$operador_id == operador, ]$fecha_produccion), ]
# Procesar cada lote del operador (necesita contexto del historial)
for (i in 1:nrow(lotes_operador)) {
lote_actual <- lotes_operador[i, ]
# Historial hasta este punto (para análisis de tendencias)
historial_hasta_ahora <- lotes_operador[1:i, ]
# Generar alertas
resultado_alertas <- generar_alertas_lote(lote_actual, historial_hasta_ahora)
# Solo guardar si hay alertas
if (length(resultado_alertas$alertas) > 0) {
fila_alerta <- data.frame(
Lote_ID = lote_actual$lote_id,
Operador = operador,
Fecha = lote_actual$fecha_produccion,
Producto = lote_actual$producto_tipo,
Prioridad = resultado_alertas$prioridad,
N_Alertas = length(resultado_alertas$alertas),
Alertas = paste(resultado_alertas$alertas, collapse = " | "),
stringsAsFactors = FALSE
)
alertas_sistema <- rbind(alertas_sistema, fila_alerta)
}
}
}
cat("Procesamiento completado.\n")
#> Procesamiento completado.
#> Total de alertas generadas: 81
#> === RESUMEN DE ALERTAS POR PRIORIDAD ===
tabla_prioridades <- table(alertas_sistema$Prioridad)
for (prioridad in c("CRÍTICA", "ALTA", "MEDIA")) {
if (prioridad %in% names(tabla_prioridades)) {
cat(prioridad, ":", tabla_prioridades[prioridad], "alertas\n")
} else {
cat(prioridad, ": 0 alertas\n")
}
}
#> CRÍTICA : 17 alertas
#> ALTA : 40 alertas
#> MEDIA : 24 alertas
# Mostrar alertas críticas
alertas_criticas <- alertas_sistema[alertas_sistema$Prioridad == "CRÍTICA", ]
if (nrow(alertas_criticas) > 0) {
cat("\n=== ALERTAS CRÍTICAS ===\n")
kable(head(alertas_criticas, 5),
caption = "Alertas que Requieren Atención Inmediata")
} else {
cat("\n¡No hay alertas críticas en el sistema!\n")
}
#>
#> === ALERTAS CRÍTICAS ===
Lote_ID | Operador | Fecha | Producto | Prioridad | N_Alertas | Alertas | |
---|---|---|---|---|---|---|---|
2 | LOTE_063 | OP_010 | 2025-02-07 | Acido_Sulfurico | CRÍTICA | 2 | CRÍTICO: pH extremadamente bajo | ADVERTENCIA: Temperatura alta |
3 | LOTE_064 | OP_010 | 2025-02-07 | Acido_Nitrico | CRÍTICA | 2 | CRÍTICO: pH extremadamente bajo | ADVERTENCIA: Temperatura alta |
4 | LOTE_126 | OP_010 | 2025-03-15 | Acido_Nitrico | CRÍTICA | 2 | CRÍTICO: pH extremadamente bajo | ADVERTENCIA: Temperatura alta |
5 | LOTE_137 | OP_010 | 2025-03-22 | Acido_Sulfurico | CRÍTICA | 2 | CRÍTICO: pH extremadamente bajo | ADVERTENCIA: Temperatura alta |
7 | LOTE_096 | OP_017 | 2025-02-26 | Acido_Nitrico | CRÍTICA | 2 | CRÍTICO: pH extremadamente bajo | ADVERTENCIA: Temperatura alta |
#>
#> Este ejemplo demuestra por qué los bucles son necesarios:
#> - Lógica compleja con múltiples condicionales
#> - Análisis contextual (historial del operador)
#> - Dependencia entre iteraciones (tendencias temporales)
#> - Imposible de vectorizar manteniendo la misma funcionalidad
# Función que integra todo lo aprendido
analisis_planta_completo <- function(datos, incluir_alertas = TRUE, incluir_optimizacion = FALSE) {
cat("=== ANÁLISIS INTEGRAL DE PLANTA QUÍMICA ===\n")
cat("Iniciando análisis automatizado con sentencias iterativas...\n\n")
# Contenedores para resultados
resultados <- list()
# 1. ANÁLISIS POR PRODUCTOS (bucle for)
cat("1. ANÁLISIS POR PRODUCTOS\n")
tipos <- unique(datos$producto_tipo)
analisis_productos <- data.frame()
for (tipo in tipos) {
datos_tipo <- datos[datos$producto_tipo == tipo, ]
# Calcular métricas clave
n_lotes <- nrow(datos_tipo)
ph_promedio <- mean(datos_tipo$ph_final, na.rm = TRUE)
temp_promedio <- mean(datos_tipo$temperatura_reaccion, na.rm = TRUE)
conc_promedio <- mean(datos_tipo$concentracion_producto, na.rm = TRUE)
tasa_exito <- mean(datos_tipo$control_calidad_pasa) * 100
# Clasificar rendimiento
if (tasa_exito >= 95) {
status <- "Excelente"
} else if (tasa_exito >= 85) {
status <- "Bueno"
} else {
status <- "Requiere mejora"
}
fila <- data.frame(
Producto = tipo,
N_Lotes = n_lotes,
pH_Promedio = round(ph_promedio, 2),
Temp_Promedio = round(temp_promedio, 1),
Conc_Promedio = round(conc_promedio, 1),
Tasa_Exito = round(tasa_exito, 1),
Status = status
)
analisis_productos <- rbind(analisis_productos, fila)
}
resultados$productos <- analisis_productos
cat(" Completado:", length(tipos), "productos analizados\n\n")
# 2. CONTROL DE CALIDAD ITERATIVO (bucle while)
cat("2. CONTROL DE CALIDAD ITERATIVO\n")
datos_temp <- datos
criterio_pH <- 2.0
criterio_temp <- 85.0
iteraciones <- 0
objetivo_aprobacion <- 0.88
while (iteraciones < 5) {
iteraciones <- iteraciones + 1
# Aplicar criterios
cumple_criterios <- (datos_temp$ph_final >= 0.5 & datos_temp$ph_final <= 13.5) &
(datos_temp$temperatura_reaccion <= criterio_temp) &
(datos_temp$presion_bar >= 1.0 & datos_temp$presion_bar <= 6.0)
tasa_actual <- mean(cumple_criterios)
if (tasa_actual >= objetivo_aprobacion) {
break
} else {
criterio_temp <- criterio_temp + 1.0
}
}
resultados$control_iterativo <- list(
iteraciones = iteraciones,
criterio_temp_final = criterio_temp,
tasa_final = round(tasa_actual * 100, 1)
)
cat(" Completado en", iteraciones, "iteraciones\n")
cat(" Tasa final de aprobación:", round(tasa_actual * 100, 1), "%\n\n")
# 3. CLASIFICACIÓN AUTOMÁTICA (if/else complejos)
cat("3. CLASIFICACIÓN AUTOMÁTICA DE LOTES\n")
clasificaciones <- character(nrow(datos))
for (i in 1:nrow(datos)) {
lote <- datos[i, ]
score <- 100
# Evaluaciones específicas por producto
if (lote$producto_tipo == "Acido_Sulfurico") {
if (lote$ph_final > 2.0) score <- score - 30
} else if (lote$producto_tipo == "Soda_Caustica") {
if (lote$ph_final < 12.0) score <- score - 30
}
# Evaluación de temperatura
if (lote$temperatura_reaccion > 80) score <- score - 15
if (lote$temperatura_reaccion < 50) score <- score - 10
# Evaluación de concentración
if (lote$concentracion_producto < 40) score <- score - 25
# Clasificación final
if (score >= 90) {
clasificaciones[i] <- "Premium"
} else if (score >= 75) {
clasificaciones[i] <- "Estándar"
} else if (score >= 60) {
clasificaciones[i] <- "Aceptable"
} else {
clasificaciones[i] <- "Revisar"
}
}
tabla_clasificaciones <- table(clasificaciones)
resultados$clasificaciones <- tabla_clasificaciones
cat(" Clasificaciones generadas:\n")
for (clase in names(tabla_clasificaciones)) {
pct <- round((tabla_clasificaciones[clase] / nrow(datos)) * 100, 1)
cat(" ", clase, ":", tabla_clasificaciones[clase], "(", pct, "%)\n")
}
cat("\n")
# 4. ALERTAS DEL SISTEMA (opcional)
if (incluir_alertas) {
cat("4. SISTEMA DE ALERTAS\n")
alertas_criticas <- 0
alertas_medias <- 0
for (i in 1:nrow(datos)) {
lote <- datos[i, ]
# Alertas críticas
if ((lote$ph_final < 1.0 && lote$producto_tipo == "Acido_Sulfurico") ||
(lote$temperatura_reaccion > 85) ||
(lote$presion_bar > 5.5)) {
alertas_criticas <- alertas_criticas + 1
}
# Alertas medias
if ((lote$concentracion_producto < 30) ||
(lote$tiempo_reaccion_horas > 10)) {
alertas_medias <- alertas_medias + 1
}
}
resultados$alertas <- list(
criticas = alertas_criticas,
medias = alertas_medias,
total = alertas_criticas + alertas_medias
)
cat(" Alertas críticas:", alertas_criticas, "\n")
cat(" Alertas medias:", alertas_medias, "\n")
cat(" Total alertas:", alertas_criticas + alertas_medias, "\n\n")
}
# 5. REPORTE FINAL
cat("=== REPORTE EJECUTIVO ===\n")
total_lotes <- nrow(datos)
lotes_exitosos <- sum(datos$control_calidad_pasa)
tasa_exito_general <- round((lotes_exitosos / total_lotes) * 100, 1)
cat("Total de lotes procesados:", total_lotes, "\n")
cat("Lotes exitosos:", lotes_exitosos, "\n")
cat("Tasa de éxito general:", tasa_exito_general, "%\n")
mejor_producto <- resultados$productos$Producto[which.max(resultados$productos$Tasa_Exito)]
cat("Producto con mejor rendimiento:", mejor_producto, "\n")
if (incluir_alertas) {
if (resultados$alertas$criticas == 0) {
cat("Estado general: SIN ALERTAS CRÍTICAS\n")
} else {
cat("Estado general: ATENCIÓN REQUERIDA (", resultados$alertas$criticas, "alertas críticas)\n")
}
}
return(invisible(resultados))
}
# Ejecutar análisis completo
cat("Ejecutando análisis integral de la planta química...\n\n")
#> Ejecutando análisis integral de la planta química...
#> === ANÁLISIS INTEGRAL DE PLANTA QUÍMICA ===
#> Iniciando análisis automatizado con sentencias iterativas...
#>
#> 1. ANÁLISIS POR PRODUCTOS
#> Completado: 5 productos analizados
#>
#> 2. CONTROL DE CALIDAD ITERATIVO
#> Completado en 1 iteraciones
#> Tasa final de aprobación: 92.7 %
#>
#> 3. CLASIFICACIÓN AUTOMÁTICA DE LOTES
#> Clasificaciones generadas:
#> Aceptable : 8 ( 5.3 %)
#> Estándar : 44 ( 29.3 %)
#> Premium : 98 ( 65.3 %)
#>
#> 4. SISTEMA DE ALERTAS
#> Alertas críticas: 15
#> Alertas medias: 34
#> Total alertas: 49
#>
#> === REPORTE EJECUTIVO ===
#> Total de lotes procesados: 150
#> Lotes exitosos: 138
#> Tasa de éxito general: 92 %
#> Producto con mejor rendimiento: Polimero_PVC
#> Estado general: ATENCIÓN REQUERIDA ( 15 alertas críticas)
# Crear visualizaciones usando los resultados del análisis iterativo
library(gridExtra)
# Gráfico 1: Rendimiento por producto (resultado del bucle for)
p1 <- ggplot(resultados_completos$productos, aes(x = reorder(Producto, Tasa_Exito),
y = Tasa_Exito, fill = Status)) +
geom_col(alpha = 0.8) +
geom_text(aes(label = paste0(Tasa_Exito, "%")), hjust = -0.1, color = "#2c3e50", fontface = "bold") +
coord_flip() +
labs(
title = "Análisis de Rendimiento por Producto",
subtitle = "Generado automáticamente con bucles for",
x = "Tipo de Producto",
y = "Tasa de Éxito (%)"
) +
scale_fill_manual(values = c("Excelente" = "#27ae60", "Bueno" = "#f39c12", "Requiere mejora" = "#e74c3c")) +
theme(legend.position = "bottom")
# Gráfico 2: Distribución de clasificaciones (resultado de if/else)
clasificaciones_df <- data.frame(
Clasificacion = names(resultados_completos$clasificaciones),
Cantidad = as.numeric(resultados_completos$clasificaciones)
)
p2 <- ggplot(clasificaciones_df, aes(x = reorder(Clasificacion, Cantidad), y = Cantidad, fill = Clasificacion)) +
geom_col(alpha = 0.8) +
geom_text(aes(label = Cantidad), hjust = -0.1, color = "#2c3e50", fontface = "bold") +
coord_flip() +
labs(
title = "Clasificación Automática de Lotes",
subtitle = "Generado con condicionales if/else complejos",
x = "Clasificación de Calidad",
y = "Número de Lotes"
) +
scale_fill_manual(values = c("Premium" = "#27ae60", "Estándar" = "#3498db",
"Aceptable" = "#f39c12", "Revisar" = "#e74c3c")) +
theme(legend.position = "none")
# Gráfico 3: Control de temperatura por turno usando análisis iterativo
datos_temp_turno <- datos_control %>%
group_by(turno) %>%
summarise(
temp_media = mean(temperatura_reaccion),
temp_sd = sd(temperatura_reaccion),
n_lotes = n(),
.groups = 'drop'
)
p3 <- ggplot(datos_temp_turno, aes(x = turno, y = temp_media, fill = turno)) +
geom_col(alpha = 0.8) +
geom_errorbar(aes(ymin = temp_media - temp_sd, ymax = temp_media + temp_sd),
width = 0.2, color = "#2c3e50") +
geom_text(aes(label = paste0(round(temp_media, 1), "°C")), vjust = -0.5,
color = "#2c3e50", fontface = "bold") +
labs(
title = "Control de Temperatura por Turno",
subtitle = "Análisis de variabilidad para optimización de procesos",
x = "Turno de Trabajo",
y = "Temperatura Media (°C)"
) +
scale_fill_manual(values = c("Mañana" = "#e8f4f8", "Tarde" = "#a73c3c", "Noche" = "#2c3e50")) +
theme(legend.position = "none")
# Mostrar gráficos
grid.arrange(p1, p2, ncol = 2)
print(p3)
Escenario: Usted es el nuevo Jefe de Control de Calidad de la planta química. Debe crear un sistema automatizado que se ejecute diariamente.
Requisitos del Sistema:
Bucle for: Generar reporte diario por cada operador (eficiencia, lotes procesados, problemas)
Bucle while: Implementar sistema de mejora continua que ajuste automáticamente parámetros hasta alcanzar 95% de aprobación
Condicionales if/else: Crear sistema de clasificación de operadores en 4 categorías (Excelente, Bueno, Regular, Crítico)
Integración: El sistema debe generar alertas automáticas y sugerir acciones correctivas
Entrega: Código R funcional que procese todos los datos y genere un reporte ejecutivo completo.
# SOLUCIÓN DEL PROYECTO FINAL
sistema_control_calidad_diario <- function(datos) {
cat("=== SISTEMA AUTOMATIZADO DE CONTROL DE CALIDAD ===\n")
cat("Fecha de ejecución:", Sys.Date(), "\n\n")
# PARTE 1: ANÁLISIS POR OPERADOR (bucle for)
cat("PARTE 1: ANÁLISIS DE DESEMPEÑO POR OPERADOR\n")
cat(paste(rep("=", 50), collapse = ""), "\n")
operadores <- unique(datos$operador_id)
reporte_operadores <- data.frame()
for (operador in operadores) {
datos_op <- datos[datos$operador_id == operador, ]
# Métricas de desempeño
n_lotes <- nrow(datos_op)
lotes_exitosos <- sum(datos_op$control_calidad_pasa)
tasa_exito <- (lotes_exitosos / n_lotes) * 100
# Variabilidad en procesos (CORRECCIÓN: manejar NA y casos de n=1)
if (n_lotes > 1) {
cv_temperatura <- (sd(datos_op$temperatura_reaccion, na.rm = TRUE) /
mean(datos_op$temperatura_reaccion, na.rm = TRUE)) * 100
cv_concentracion <- (sd(datos_op$concentracion_producto, na.rm = TRUE) /
mean(datos_op$concentracion_producto, na.rm = TRUE)) * 100
} else {
cv_temperatura <- 0
cv_concentracion <- 0
}
# Manejar casos donde cv es NA
if (is.na(cv_temperatura)) cv_temperatura <- 99
if (is.na(cv_concentracion)) cv_concentracion <- 99
# Tiempo promedio de reacción
tiempo_promedio <- mean(datos_op$tiempo_reaccion_horas, na.rm = TRUE)
# Clasificación del operador (if/else anidados) - CORRECCIÓN
if (!is.na(tasa_exito) && !is.na(cv_temperatura) && !is.na(cv_concentracion)) {
if (tasa_exito >= 95 && cv_temperatura < 10 && cv_concentracion < 15) {
clasificacion <- "Excelente"
accion_recomendada <- "Reconocimiento público"
} else if (tasa_exito >= 85 && cv_temperatura < 15) {
clasificacion <- "Bueno"
accion_recomendada <- "Continuar con el buen trabajo"
} else if (tasa_exito >= 75) {
clasificacion <- "Regular"
accion_recomendada <- "Entrenamiento adicional requerido"
} else {
clasificacion <- "Crítico"
accion_recomendada <- "Intervención inmediata necesaria"
}
} else {
clasificacion <- "Sin_Datos"
accion_recomendada <- "Verificar datos del operador"
}
# Guardar resultados
fila_operador <- data.frame(
Operador = operador,
N_Lotes = n_lotes,
Tasa_Exito = round(tasa_exito, 1),
CV_Temperatura = round(cv_temperatura, 1),
CV_Concentracion = round(cv_concentracion, 1),
Tiempo_Promedio = round(tiempo_promedio, 2),
Clasificacion = clasificacion,
Accion = accion_recomendada,
stringsAsFactors = FALSE
)
reporte_operadores <- rbind(reporte_operadores, fila_operador)
}
# Mostrar resumen por clasificación
clasificaciones_count <- table(reporte_operadores$Clasificacion)
cat("Resumen de operadores por categoría:\n")
for (cat in names(clasificaciones_count)) {
cat(" ", cat, ":", clasificaciones_count[cat], "operadores\n")
}
cat("\n")
# PARTE 2: MEJORA CONTINUA ITERATIVA (bucle while)
cat("PARTE 2: SISTEMA DE MEJORA CONTINUA\n")
cat(paste(rep("=", 40), collapse = ""), "\n")
objetivo_global <- 0.95
criterio_temp_max <- 80.0
criterio_conc_min <- 40.0
criterio_pH_rango <- c(1.0, 13.0)
iteracion_mejora <- 0
max_iteraciones <- 8
datos_mejora <- datos
tasa_actual <- mean(datos_mejora$control_calidad_pasa, na.rm = TRUE)
while (tasa_actual < objetivo_global && iteracion_mejora < max_iteraciones) {
iteracion_mejora <- iteracion_mejora + 1
cat("Iteración de mejora", iteracion_mejora, ":\n")
cat(" Tasa actual:", round(tasa_actual * 100, 1), "%\n")
# Ajustar criterios gradualmente
if (iteracion_mejora %% 3 == 1) {
criterio_temp_max <- criterio_temp_max + 2.0
cat(" Acción: Relajar criterio de temperatura a ≤", criterio_temp_max, "°C\n")
} else if (iteracion_mejora %% 3 == 2) {
criterio_conc_min <- criterio_conc_min - 3.0
cat(" Acción: Reducir concentración mínima a ≥", criterio_conc_min, "%\n")
} else {
criterio_pH_rango[1] <- criterio_pH_rango[1] - 0.2
criterio_pH_rango[2] <- criterio_pH_rango[2] + 0.2
cat(" Acción: Ampliar rango de pH a [", criterio_pH_rango[1], ",", criterio_pH_rango[2], "]\n")
}
# Recalcular tasa con nuevos criterios (CORRECCIÓN: manejar NA)
cumple_criterios <- (datos_mejora$temperatura_reaccion <= criterio_temp_max) &
(datos_mejora$concentracion_producto >= criterio_conc_min) &
(datos_mejora$ph_final >= criterio_pH_rango[1] &
datos_mejora$ph_final <= criterio_pH_rango[2])
# Remover NA de la evaluación
cumple_criterios[is.na(cumple_criterios)] <- FALSE
tasa_actual <- mean(cumple_criterios)
cat(" Nueva tasa proyectada:", round(tasa_actual * 100, 1), "%\n\n")
}
if (tasa_actual >= objetivo_global) {
cat("ÉXITO: Objetivo de", round(objetivo_global * 100, 1), "% alcanzado en", iteracion_mejora, "iteraciones\n")
} else {
cat("ADVERTENCIA: Objetivo no alcanzado en", max_iteraciones, "iteraciones máximas\n")
}
cat("Criterios optimizados finales:\n")
cat(" - Temperatura máxima:", criterio_temp_max, "°C\n")
cat(" - Concentración mínima:", criterio_conc_min, "%\n")
cat(" - Rango pH:", criterio_pH_rango[1], "a", criterio_pH_rango[2], "\n\n")
# PARTE 3: ALERTAS Y ACCIONES AUTOMÁTICAS
cat("PARTE 3: SISTEMA DE ALERTAS AUTOMÁTICAS\n")
cat(paste(rep("=", 42), collapse = ""), "\n")
# Operadores críticos (CORRECCIÓN: filtrar NA)
operadores_criticos <- reporte_operadores[
reporte_operadores$Clasificacion == "Crítico" &
!is.na(reporte_operadores$Clasificacion),
]
n_criticos <- nrow(operadores_criticos)
cat("ALERTAS CRÍTICAS:\n")
if (n_criticos > 0) {
cat(" ATENCIÓN: ", n_criticos, " operador(es) requieren intervención inmediata:\n")
for (i in 1:n_criticos) {
cat(" -", operadores_criticos$Operador[i],
"- Tasa de éxito:", operadores_criticos$Tasa_Exito[i], "%\n")
}
} else {
cat(" ✓ No hay operadores en estado crítico\n")
}
# Productos con problemas
productos_problematicos <- reporte_operadores[
reporte_operadores$Clasificacion %in% c("Regular", "Crítico") &
!is.na(reporte_operadores$Clasificacion),
]
total_problematicos <- nrow(productos_problematicos)
cat("\nALERTAS DE PROCESO:\n")
if (total_problematicos > 0) {
pct_problematicos <- round((total_problematicos / length(operadores)) * 100, 1)
cat(" ADVERTENCIA:", total_problematicos, "operadores (", pct_problematicos, "%) necesitan atención\n")
} else {
cat(" ✓ Todos los operadores tienen desempeño aceptable\n")
}
# Recomendaciones automáticas (CORRECCIÓN: verificar que hay datos válidos)
cat("\nRECOMENDACIONES AUTOMÁTICAS:\n")
if (nrow(reporte_operadores) > 0 && !all(is.na(reporte_operadores$Tasa_Exito))) {
mejor_operador <- reporte_operadores$Operador[which.max(reporte_operadores$Tasa_Exito)]
peor_operador <- reporte_operadores$Operador[which.min(reporte_operadores$Tasa_Exito)]
cat(" 1. Operador modelo:", mejor_operador,
"- Usar como mentor para entrenamientos\n")
cat(" 2. Operador prioritario:", peor_operador,
"- Requiere programa de mejora personalizado\n")
}
if (iteracion_mejora <= 3) {
cat(" 3. Procesos: Criterios actuales son apropiados\n")
} else {
cat(" 3. Procesos: Considerar revisión de estándares de calidad\n")
}
# REPORTE FINAL
cat("\n")
cat(paste(rep("=", 60), collapse = ""), "\n")
cat("REPORTE EJECUTIVO DIARIO\n")
cat(paste(rep("=", 60), collapse = ""), "\n")
cat("Total de operadores evaluados:", length(operadores), "\n")
cat("Total de lotes procesados:", nrow(datos), "\n")
cat("Tasa de éxito general:", round(mean(datos$control_calidad_pasa, na.rm = TRUE) * 100, 1), "%\n")
cat("Operadores excelentes:", sum(reporte_operadores$Clasificacion == "Excelente", na.rm = TRUE), "\n")
cat("Operadores que necesitan atención:",
sum(reporte_operadores$Clasificacion %in% c("Regular", "Crítico"), na.rm = TRUE), "\n")
if (n_criticos == 0 && total_problematicos <= 2) {
cat("ESTADO GENERAL: ✓ OPERACIÓN NORMAL\n")
} else if (n_criticos == 0) {
cat("ESTADO GENERAL: ⚠ ATENCIÓN REQUERIDA\n")
} else {
cat("ESTADO GENERAL: 🚨 INTERVENCIÓN CRÍTICA\n")
}
# Retornar resultados para uso posterior
return(list(
operadores = reporte_operadores,
criterios_optimizados = list(
temp_max = criterio_temp_max,
conc_min = criterio_conc_min,
ph_rango = criterio_pH_rango
),
alertas = list(
criticos = n_criticos,
problematicos = total_problematicos
)
))
}
“Las sentencias iterativas son el corazón de la automatización en análisis de datos químicos. Nos permiten procesar grandes volúmenes de información con lógica compleja, manteniendo la flexibilidad para adaptarse a diferentes escenarios industriales.”
#> === COMPETENCIAS DESARROLLADAS EN ESTA CLASE ===
competencias <- data.frame(
Competencia = c(
"Bucles for básicos",
"Bucles for con análisis grupal",
"Bucles anidados",
"Bucles while condicionales",
"Bucles while iterativos",
"Condicionales simples",
"Condicionales complejos anidados",
"Funciones con iterativas",
"Optimización de código",
"Vectorización vs bucles"
),
Nivel_Dominio = c(
"Intermedio",
"Avanzado",
"Avanzado",
"Intermedio",
"Avanzado",
"Básico",
"Avanzado",
"Avanzado",
"Intermedio",
"Avanzado"
),
Aplicacion_Quimica = c(
"Análisis por productos",
"Control de calidad por grupos",
"Análisis multidimensional",
"Validación iterativa",
"Optimización de procesos",
"Clasificación de muestras",
"Sistemas de alertas",
"Automatización completa",
"Eficiencia computacional",
"Mejores prácticas"
)
)
kable(competencias,
caption = "Mapa de Competencias: Sentencias Iterativas en Química Industrial",
align = "lll")
Competencia | Nivel_Dominio | Aplicacion_Quimica |
---|---|---|
Bucles for básicos | Intermedio | Análisis por productos |
Bucles for con análisis grupal | Avanzado | Control de calidad por grupos |
Bucles anidados | Avanzado | Análisis multidimensional |
Bucles while condicionales | Intermedio | Validación iterativa |
Bucles while iterativos | Avanzado | Optimización de procesos |
Condicionales simples | Básico | Clasificación de muestras |
Condicionales complejos anidados | Avanzado | Sistemas de alertas |
Funciones con iterativas | Avanzado | Automatización completa |
Optimización de código | Intermedio | Eficiencia computacional |
Vectorización vs bucles | Avanzado | Mejores prácticas |
#>
#> === MÉTRICAS DE APRENDIZAJE ===
#> Líneas de código R escritas: ~400
#> Funciones creadas: 5
#> Datasets procesados: 1 (150 registros)
#> Bucles implementados: 15+
#> Condicionales complejos: 20+
#> Casos de uso industriales: 8
Casos de Uso Directos en la Industria Química:
Clase 5: Funciones Avanzadas para Análisis
Químico
Construiremos sobre las sentencias iterativas
para crear:
• Funciones especializadas para análisis químico
•
Librerías personalizadas para control de calidad
• Sistemas
modulares para diferentes tipos de análisis
• Documentación y
testing de funciones
• Integración con bases de datos químicas