Introducción al análisis de datos para otras carreras
Las sentencias iterativas son estructuras que ejecutan el mismo código múltiples veces, siguiendo un patrón específico.
Es como tener un robot que:
Imagina que tienes que:
Sin bucles: Escribes 50 veces el mismo código
Con bucles: Escribes el código una vez, se ejecuta 50 veces
Ventaja principal: Escribes el código una vez, funciona para todos los datos
Uso: Cuando sabes exactamente cuántas veces repetir
Ejemplo: "Calcula la molaridad para las 15 muestras"
→ Sabemos que son exactamente 15
Uso: Cuando no sabes cuántas repeticiones necesitas
Ejemplo: "Agrega base hasta que el pH sea 7"
→ No sabemos cuántas gotas necesitaremos
Aspecto | Bucle for | Bucle while |
---|---|---|
¿Cuántas veces? | Número conocido | Número desconocido |
Condición | Hasta terminar la lista | Mientras se cumpla algo |
Ejemplo químico | 20 muestras → 20 repeticiones | Hasta pH = 7 → ? repeticiones |
Riesgo | Muy seguro | Puede ser infinito |
for (variable in lista) { # Código que se repite # Puede usar la variable }
Componentes:
# Saludar a 3 estudiantes estudiantes <- c("Ana", "Carlos", "María") for (nombre in estudiantes) { print(paste("Hola", nombre)) } # Resultado: # "Hola Ana" # "Hola Carlos" # "Hola María"
# Convertir temperaturas de °C a Kelvin temperaturas_C <- c(25, 30, 35, 40) for (temp_C in temperaturas_C) { temp_K <- temp_C + 273.15 print(paste(temp_C, "°C =", temp_K, "K")) } # Resultado: # "25 °C = 298.15 K" # "30 °C = 303.15 K" # "35 °C = 308.15 K" # "40 °C = 313.15 K"
# Calcular el cuadrado de números del 1 al 5 for (numero in 1:5) { cuadrado <- numero^2 print(paste(numero, "al cuadrado =", cuadrado)) } # Resultado: # "1 al cuadrado = 1" # "2 al cuadrado = 4" # "3 al cuadrado = 9" # "4 al cuadrado = 16" # "5 al cuadrado = 25"
Lo importante: El código dentro del bucle se ejecuta una vez para cada elemento de la lista
# Datos de diferentes soluciones moles_soluto <- c(0.5, 1.2, 0.8, 2.0) litros_solucion <- c(1.0, 2.0, 0.5, 1.5) # Calcular molaridad para cada solución for (i in 1:4) { molaridad <- moles_soluto[i] / litros_solucion[i] print(paste("Solución", i, ": M =", round(molaridad, 2))) } # Resultado: # "Solución 1 : M = 0.5" # "Solución 2 : M = 0.6" # "Solución 3 : M = 1.6" # "Solución 4 : M = 1.33"
# Valores de pH de diferentes muestras valores_ph <- c(3.2, 7.1, 10.5, 6.8, 2.1) for (ph in valores_ph) { if (ph < 7) { tipo <- "ácida" } else if (ph == 7) { tipo <- "neutra" } else { tipo <- "básica" } print(paste("pH", ph, "es", tipo)) } # Resultado: # "pH 3.2 es ácida" # "pH 7.1 es básica" # "pH 10.5 es básica" # "pH 6.8 es ácida" # "pH 2.1 es ácida"
# Concentraciones medidas (mg/L) concentraciones <- c(95, 102, 88, 110, 98) limite_inferior <- 90 limite_superior <- 105 for (i in 1:length(concentraciones)) { conc <- concentraciones[i] if (conc >= limite_inferior && conc <= limite_superior) { estado <- "APROBADA" } else { estado <- "RECHAZADA" } print(paste("Muestra", i, ":", conc, "mg/L -", estado)) } # Resultado: # "Muestra 1 : 95 mg/L - APROBADA" # "Muestra 2 : 102 mg/L - APROBADA" # "Muestra 3 : 88 mg/L - RECHAZADA" # "Muestra 4 : 110 mg/L - RECHAZADA" # "Muestra 5 : 98 mg/L - APROBADA"
# Valores esperados vs medidos valores_esperados <- c(100, 50, 75, 25) valores_medidos <- c(98, 52, 73, 26) for (i in 1:4) { esperado <- valores_esperados[i] medido <- valores_medidos[i] error_porcentual <- abs(esperado - medido) / esperado * 100 print(paste("Muestra", i, ": Error =", round(error_porcentual, 1), "%")) } # Resultado: # "Muestra 1 : Error = 2 %" # "Muestra 2 : Error = 4 %" # "Muestra 3 : Error = 2.7 %" # "Muestra 4 : Error = 4 %"
Patrón común:
while (condición) { # Código que se repite # IMPORTANTE: cambiar algo que afecte la condición }
Funcionamiento:
# Contar del 1 al 5 contador <- 1 while (contador <= 5) { print(paste("Número:", contador)) contador <- contador + 1 # ¡MUY IMPORTANTE! } # Resultado: # "Número: 1" # "Número: 2" # "Número: 3" # "Número: 4" # "Número: 5"
⚠️ CUIDADO: Si no cambias la variable en el bucle, se ejecutará infinitamente
# Diluir hasta concentración aceptable concentracion <- 500 # mg/L (muy alta) objetivo <- 100 # mg/L (concentración deseada) iteracion <- 0 print(paste("Concentración inicial:", concentracion, "mg/L")) while (concentracion > objetivo) { # Diluir (agregar mismo volumen de agua) concentracion <- concentracion / 2 iteracion <- iteracion + 1 print(paste("Dilución", iteracion, ":", round(concentracion, 1), "mg/L")) } print(paste("¡Listo! Concentración final:", round(concentracion, 1), "mg/L")) # Resultado: # "Concentración inicial: 500 mg/L" # "Dilución 1 : 250 mg/L" # "Dilución 2 : 125 mg/L" # "Dilución 3 : 62.5 mg/L" # "¡Listo! Concentración final: 62.5 mg/L"
# Simular ajuste de pH agregando base ph_actual <- 4.5 # pH inicial (ácido) ph_objetivo <- 7.0 # pH neutro deseado gotas_base <- 0 print(paste("pH inicial:", ph_actual)) while (ph_actual < ph_objetivo) { # Agregar una gota de base (simulado) ph_actual <- ph_actual + 0.3 gotas_base <- gotas_base + 1 print(paste("Gota", gotas_base, ": pH =", round(ph_actual, 1))) } print(paste("¡pH neutro alcanzado!")) print(paste("Total de gotas utilizadas:", gotas_base))
# Esperar a que la muestra se enfríe temperatura <- 80 # °C (muy caliente) temp_segura <- 25 # °C (temperatura ambiente) minutos <- 0 print(paste("Temperatura inicial:", temperatura, "°C")) while (temperatura > temp_segura) { # Simular enfriamiento (pierde 5°C por minuto) temperatura <- temperatura - 5 minutos <- minutos + 1 print(paste("Minuto", minutos, ":", temperatura, "°C")) } print("¡Muestra lista para manipular!")
# Repetir medición hasta obtener precisión aceptable mediciones <- c() error_aceptable <- 2 # % error máximo permitido intentos <- 0 # Simular mediciones con diferentes errores errores_simulados <- c(5, 3, 1.5, 0.8) while (length(mediciones) == 0 || tail(mediciones, 1) > error_aceptable) { intentos <- intentos + 1 # Simular medición (en la realidad sería experimental) error_actual <- errores_simulados[intentos] mediciones <- c(mediciones, error_actual) print(paste("Intento", intentos, ": Error =", error_actual, "%")) if (error_actual <= error_aceptable) { print("¡Precisión aceptable alcanzada!") } else { print("Repetir medición...") } } print(paste("Total de intentos:", intentos))
Ventaja de while: Se adapta automáticamente a las condiciones, sin importar cuántos pasos requiera
Prevenir bucles infinitos:
Criterio principal: Conoces el número exacto de repeticiones
Situaciones típicas:
# Tengo exactamente 6 muestras ph_muestras <- c(6.5, 7.2, 5.8, 8.1, 7.0, 6.9) # Uso for porque sé que son 6 for (ph in ph_muestras) { if (ph < 7) { print(paste("pH", ph, "es ácido")) } else { print(paste("pH", ph, "es básico/neutro")) } }
Criterio principal: No sabes cuántas repeticiones necesitas
Situaciones típicas:
# No sé cuántas diluciones necesito concentracion <- 1000 # mg/L (muy alta) limite_seguro <- 50 # mg/L # Uso while porque no sé cuántas veces diluir while (concentracion > limite_seguro) { concentracion <- concentracion * 0.7 # Diluir 30% print(paste("Nueva concentración:", round(concentracion, 1), "mg/L")) }
Regla de seguridad para while: Siempre incluir un límite máximo de iteraciones
# ❌ MAL - Bucle infinito contador <- 1 while (contador <= 5) { print(contador) # ¡Olvido incrementar contador! } # Este bucle nunca termina # ✅ BIEN - Actualizar la variable contador <- 1 while (contador <= 5) { print(contador) contador <- contador + 1 # ¡Importante! }
# ❌ MAL - Índice fuera de rango datos <- c(10, 20, 30) for (i in 1:5) { # ¡Solo hay 3 elementos! print(datos[i]) # Error en i=4 y i=5 } # ✅ BIEN - Usar length() datos <- c(10, 20, 30) for (i in 1:length(datos)) { print(datos[i]) }
# ❌ MAL - Condición que nunca cambia ph <- 5 while (ph != 7) { # ph nunca será exactamente 7 ph <- ph + 0.3 # Puede saltar sobre 7 } # ✅ BIEN - Usar rango de tolerancia ph <- 5 while (abs(ph - 7) > 0.1) { # Cerca de 7 ph <- ph + 0.3 }
# ❌ MAL - No verificar datos concentraciones <- c(50, NA, 75, 100) for (conc in concentraciones) { molaridad <- conc / 58.44 # Error con NA print(molaridad) } # ✅ BIEN - Validar antes de usar concentraciones <- c(50, NA, 75, 100) for (conc in concentraciones) { if (!is.na(conc)) { molaridad <- conc / 58.44 print(paste("Molaridad:", round(molaridad, 3))) } else { print("Dato faltante - saltando") } }
# ❌ MAL - Cambiar la lista durante el bucle valores <- c(1, 2, 3, 4, 5) for (i in 1:length(valores)) { if (valores[i] > 3) { valores <- valores[-i] # ¡Modifica la lista! } } # ✅ BIEN - Crear nueva lista valores <- c(1, 2, 3, 4, 5) valores_filtrados <- c() for (valor in valores) { if (valor <= 3) { valores_filtrados <- c(valores_filtrados, valor) } }
Situaciones apropiadas:
# Clasificación compleja que requiere bucle muestras <- data.frame( ph = c(6.5, 8.2, 3.1, 7.0), temperatura = c(25, 45, 20, 30), concentracion = c(100, 200, 50, 150) ) for (i in 1:nrow(muestras)) { # Lógica compleja que combina múltiples factores if (muestras$ph[i] < 6 && muestras$temperatura[i] > 40) { clasificacion <- "Peligrosa" } else if (muestras$concentracion[i] > 180) { clasificacion <- "Muy concentrada" } else if (abs(muestras$ph[i] - 7) < 0.5) { clasificacion <- "Ideal" } else { clasificacion <- "Normal" } print(paste("Muestra", i, ":", clasificacion)) }
Situaciones para vectorización:
# Conversión simple - mejor SIN bucle temperaturas_C <- c(25, 30, 35, 40, 45) # ❌ Innecesariamente complejo con bucle temperaturas_K_bucle <- c() for (temp in temperaturas_C) { temperaturas_K_bucle <- c(temperaturas_K_bucle, temp + 273.15) } # ✅ Más simple con vectorización temperaturas_K_simple <- temperaturas_C + 273.15 # Ambos dan el mismo resultado: print(temperaturas_K_simple) # [1] 298.15 303.15 308.15 313.15 318.15
Usa bucles si necesitas:
Usa vectorización si solo necesitas:
# Mostrar progreso durante el bucle muestras <- c(45, 67, 89, 23, 56) for (i in 1:length(muestras)) { print(paste("Procesando muestra", i, "de", length(muestras))) resultado <- muestras[i] * 2.5 print(paste("Valor:", muestras[i], "-> Resultado:", resultado)) print("---") # Separador visual }
# Primero probar con pocos datos datos_prueba <- c(10, 20, 30) # Solo 3 elementos for (valor in datos_prueba) { resultado <- valor / 5 print(paste(valor, "/ 5 =", resultado)) } # Si funciona bien, usar con datos completos datos_completos <- c(10, 20, 30, 40, 50, 60, 70, 80)
# Agregar contador de seguridad concentracion <- 1000 objetivo <- 50 iteraciones <- 0 max_iteraciones <- 20 # Límite de seguridad while (concentracion > objetivo && iteraciones < max_iteraciones) { concentracion <- concentracion * 0.8 iteraciones <- iteraciones + 1 print(paste("Iteración", iteraciones, ": concentración =", round(concentracion, 1))) } if (iteraciones >= max_iteraciones) { print("ADVERTENCIA: Se alcanzó el límite máximo de iteraciones") }
# Función simple de validación validar_datos_quimicos <- function(datos) { errores <- c() # Verificar que no estén vacíos if (length(datos) == 0) { errores <- c(errores, "No hay datos para procesar") } # Verificar valores NA if (any(is.na(datos))) { errores <- c(errores, "Hay valores faltantes (NA)") } # Verificar valores negativos (si aplica) if (any(datos < 0, na.rm = TRUE)) { errores <- c(errores, "Hay valores negativos") } return(errores) } # Usar la validación concentraciones <- c(50, 75, NA, 100, -5) errores <- validar_datos_quimicos(concentraciones) if (length(errores) > 0) { print("ERRORES ENCONTRADOS:") for (error in errores) { print(paste("-", error)) } } else { print("Datos válidos - procesando...") # Aquí iría el bucle principal }
# Continuar procesando aunque haya errores individuales valores <- c(100, 0, 50, NA, 75) for (i in 1:length(valores)) { print(paste("Procesando elemento", i)) valor <- valores[i] # Verificar casos problemáticos if (is.na(valor)) { print(" Saltando: valor faltante") next # Continúa con el siguiente elemento } if (valor == 0) { print(" Saltando: valor cero") next } # Procesar normalmente resultado <- 100 / valor print(paste(" Resultado:", round(resultado, 2))) }
Bucle for:
Bucle while:
# Molaridad M = moles / litros # Dilución C1 * V1 = C2 * V2 # Porcentaje de error error % = |valor_real - valor_medido| / valor_real * 100 # Conversión de temperatura K = °C + 273.15
Trabajaremos juntos paso a paso:
# Ejemplos de datos típicos # Vector de pH ph_muestras <- c(6.5, 7.2, 5.8, 8.1, 7.0) # Vector de concentraciones (mg/L) concentraciones <- c(45, 67, 89, 23, 56) # Vector de temperaturas (°C) temperaturas <- c(25, 30, 35, 40) # Data frame con múltiples variables datos_lab <- data.frame( muestra_id = c("A1", "A2", "A3"), ph = c(6.5, 7.2, 5.8), concentracion = c(45, 67, 89), temperatura = c(25, 30, 35) )
# 1. Cargar/crear datos datos <- c(...) # 2. Validar datos (opcional) if (any(is.na(datos))) { print("Hay datos faltantes") } # 3. Procesar con bucle for (valor in datos) { # Aplicar fórmula o lógica resultado <- calcular_algo(valor) # Mostrar resultado print(paste("Valor:", valor, "-> Resultado:", resultado)) } # 4. Resumen final print("Procesamiento completado")
Para aprovechar al máximo:
Importante: El notebook es un taller práctico donde trabajamos juntos. Es diferente de los laboratorios evaluables que harán individualmente más adelante
Trabajaremos en R con un notebook que incluye:
Formato del notebook:
¿Preguntas sobre sentencias iterativas?