R

R

Tutorial R: Estructuras de control iterativo

Aprende a usar bucles for, while, repeat y vectorización en R para controlar la iteración y optimizar tu código de forma eficiente.

Aprende R y certifícate

Bucles for con vectores y secuencias

Los bucles son estructuras fundamentales en programación que nos permiten ejecutar un bloque de código repetidamente. En R, el bucle for es una herramienta esencial para iterar sobre elementos de vectores y secuencias, permitiéndonos realizar operaciones repetitivas de manera controlada.

Estructura básica del bucle for

La sintaxis básica de un bucle for en R es:

for (variable in secuencia) {
  # Código a ejecutar en cada iteración
}

Donde:

  • variable: Es el nombre que le damos al elemento actual en cada iteración
  • secuencia: Es el conjunto de valores sobre los que queremos iterar

Iteración sobre secuencias numéricas

La forma más sencilla de crear un bucle for es utilizando una secuencia numérica. En R, podemos generar secuencias con el operador ::

# Imprime los números del 1 al 5
for (i in 1:5) {
  print(i)
}

Este código imprimirá cada número del 1 al 5 en líneas separadas. En cada iteración, la variable i toma un valor diferente de la secuencia.

También podemos crear secuencias más complejas con la función seq():

# Secuencia de 0 a 10 en incrementos de 2
for (num in seq(0, 10, by = 2)) {
  print(paste("El número es:", num))
}

Este bucle imprimirá los valores 0, 2, 4, 6, 8 y 10, con un mensaje descriptivo.

Iteración sobre vectores

Una de las aplicaciones más comunes de los bucles for en R es iterar sobre los elementos de un vector:

# Crear un vector de frutas
frutas <- c("manzana", "plátano", "naranja", "uva", "pera")

# Iterar sobre cada fruta
for (fruta in frutas) {
  print(paste("Me gusta comer", fruta))
}

En este ejemplo, la variable fruta toma el valor de cada elemento del vector frutas en cada iteración.

Acceso por índice

A veces necesitamos acceder a la posición de los elementos, no solo a su valor. Podemos hacerlo iterando sobre los índices del vector:

nombres <- c("Ana", "Carlos", "Elena", "David")

# Iterar usando índices
for (i in 1:length(nombres)) {
  print(paste(i, ":", nombres[i]))
}

Este código imprimirá cada nombre junto con su posición en el vector. La función length() nos devuelve el número de elementos en el vector.

Modificación de vectores con bucles for

Podemos usar bucles for para crear o modificar vectores:

# Crear un vector vacío
resultados <- numeric(5)  # Vector de 5 ceros

# Llenar el vector con los cuadrados de los números del 1 al 5
for (i in 1:5) {
  resultados[i] <- i^2
}

print(resultados)  # Imprime: 1 4 9 16 25

En este ejemplo, creamos un vector numérico vacío y luego asignamos valores calculados a cada posición.

Iteración sobre matrices

Los bucles for también pueden utilizarse para recorrer matrices, aunque generalmente necesitaremos bucles anidados:

# Crear una matriz 3x3
matriz <- matrix(1:9, nrow = 3)

# Iterar por filas y columnas
for (fila in 1:nrow(matriz)) {
  for (columna in 1:ncol(matriz)) {
    print(paste("Elemento en posición [", fila, ",", columna, "]:", matriz[fila, columna]))
  }
}

Este código recorre cada elemento de la matriz e imprime su posición y valor.

Uso de break y next

R proporciona las palabras clave break y next para controlar el flujo dentro de los bucles:

  • break: Sale completamente del bucle
  • next: Salta a la siguiente iteración
# Ejemplo de break
for (i in 1:10) {
  if (i > 5) {
    break  # Sale del bucle cuando i es mayor que 5
  }
  print(i)
}

# Ejemplo de next
for (i in 1:10) {
  if (i %% 2 == 0) {
    next  # Salta los números pares
  }
  print(i)  # Solo imprime números impares
}

Consideraciones de rendimiento

Aunque los bucles for son útiles para aprender y para operaciones simples, en R suelen ser menos eficientes que las operaciones vectorizadas:

# Enfoque con bucle for
numeros <- 1:1000
suma <- 0
for (num in numeros) {
  suma <- suma + num
}

# Enfoque vectorizado (más eficiente)
suma_vectorizada <- sum(numeros)

El segundo enfoque es mucho más rápido, especialmente con conjuntos de datos grandes, pero los bucles for siguen siendo útiles para entender la lógica de iteración y para casos donde necesitamos un control preciso sobre cada paso.

Ejemplo práctico: Análisis de datos

Veamos un ejemplo sencillo de cómo usar un bucle for para analizar datos:

# Temperaturas diarias de una semana (en grados Celsius)
temperaturas <- c(22, 25, 19, 21, 24, 26, 23)
dias <- c("Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo")

# Analizar cada temperatura
for (i in 1:length(temperaturas)) {
  temp <- temperaturas[i]
  dia <- dias[i]
  
  mensaje <- paste("El", dia, "la temperatura fue de", temp, "°C")
  
  # Añadir un comentario sobre la temperatura
  if (temp > 25) {
    mensaje <- paste(mensaje, "- Hizo calor")
  } else if (temp < 20) {
    mensaje <- paste(mensaje, "- Hizo frío")
  } else {
    mensaje <- paste(mensaje, "- Temperatura agradable")
  }
  
  print(mensaje)
}

Este ejemplo muestra cómo podemos combinar bucles for con estructuras condicionales para analizar datos de manera sistemática.

while y repeat para iteración condicional

Mientras que los bucles for son ideales cuando conocemos de antemano el número de iteraciones, R también ofrece estructuras de control para situaciones donde necesitamos repetir código hasta que se cumpla (o deje de cumplirse) una condición específica. Estas estructuras son los bucles while y repeat.

Bucle while

El bucle while ejecuta un bloque de código repetidamente mientras una condición especificada sea verdadera. Su sintaxis básica es:

while (condición) {
  # Código a ejecutar mientras la condición sea TRUE
}

Un ejemplo sencillo sería un contador que se incrementa hasta alcanzar un valor determinado:

contador <- 1

while (contador <= 5) {
  print(paste("Iteración número:", contador))
  contador <- contador + 1  # Importante: actualizar la variable de control
}

Este código imprimirá los números del 1 al 5. Observa que debemos actualizar manualmente la variable que controla la condición (contador), de lo contrario crearíamos un bucle infinito.

Ejemplo práctico: Aproximación a un valor

Podemos usar while para implementar algoritmos que requieren aproximaciones sucesivas:

objetivo <- 1000
valor <- 1
iteraciones <- 0

while (valor < objetivo) {
  valor <- valor * 2
  iteraciones <- iteraciones + 1
  print(paste("Iteración", iteraciones, ": valor =", valor))
}

print(paste("Se necesitaron", iteraciones, "duplicaciones para superar", objetivo))

Este código duplica un valor repetidamente hasta superar un objetivo, contando cuántas iteraciones fueron necesarias.

Precauciones con while

Los bucles while requieren especial cuidado para evitar bucles infinitos. Siempre debemos asegurarnos de que:

  1. La condición eventualmente se volverá FALSE
  2. Las variables en la condición se actualizan dentro del bucle
# Ejemplo de protección contra bucles infinitos
max_iteraciones <- 1000
contador <- 0

while (contador < max_iteraciones && algunaCondicion()) {
  # Código del bucle
  contador <- contador + 1
  
  if (contador == max_iteraciones) {
    warning("Se alcanzó el número máximo de iteraciones")
  }
}

Bucle repeat

El bucle repeat es la estructura de iteración más básica en R. Ejecuta un bloque de código indefinidamente hasta que se encuentra una instrucción break. Su sintaxis es:

repeat {
  # Código a ejecutar repetidamente
  if (condición_de_salida) {
    break  # Sale del bucle cuando se cumple la condición
  }
}

A diferencia de while, el bucle repeat no tiene una condición inicial, por lo que siempre requiere una instrucción break para terminar:

contador <- 1

repeat {
  print(paste("Número:", contador))
  contador <- contador + 1
  
  if (contador > 5) {
    break  # Sale del bucle cuando contador supera 5
  }
}

Este código produce el mismo resultado que el primer ejemplo de while, imprimiendo los números del 1 al 5.

Simulación de eventos aleatorios

El bucle repeat es útil cuando no podemos predecir cuántas iteraciones serán necesarias, como en simulaciones:

# Simular lanzamientos de moneda hasta obtener 3 caras consecutivas
caras_consecutivas <- 0
lanzamientos <- 0

repeat {
  lanzamientos <- lanzamientos + 1
  resultado <- sample(c("cara", "cruz"), 1)
  print(paste("Lanzamiento", lanzamientos, ":", resultado))
  
  if (resultado == "cara") {
    caras_consecutivas <- caras_consecutivas + 1
  } else {
    caras_consecutivas <- 0  # Reiniciar contador si sale cruz
  }
  
  if (caras_consecutivas >= 3) {
    print(paste("¡Tres caras consecutivas después de", lanzamientos, "lanzamientos!"))
    break
  }
}

Este ejemplo simula lanzamientos de moneda hasta obtener tres caras consecutivas, un evento cuyo número de intentos no podemos predecir.

Combinando next y break

Tanto en while como en repeat, podemos usar next para saltar a la siguiente iteración y break para salir completamente del bucle:

numero <- 0

while (numero < 10) {
  numero <- numero + 1
  
  # Saltar los números pares
  if (numero %% 2 == 0) {
    next
  }
  
  print(paste("Procesando número impar:", numero))
  
  # Salir si encontramos el número 7
  if (numero == 7) {
    print("¡Encontrado el número 7! Terminando bucle.")
    break
  }
}

Este código procesa solo números impares y termina cuando encuentra el número 7.

Comparación entre while y repeat

Aunque while y repeat pueden usarse para resolver los mismos problemas, existen diferencias sutiles que pueden hacer que uno sea más adecuado que el otro en ciertos casos:

  • while: Es preferible cuando la condición de continuación se evalúa naturalmente al inicio de cada iteración.
  • repeat: Es más claro cuando la condición de salida se determina en algún punto dentro del bucle.
# Ejemplo con while
respuesta <- ""
while (respuesta != "salir") {
  respuesta <- readline("Escribe algo (o 'salir' para terminar): ")
  print(paste("Has escrito:", respuesta))
}

# Equivalente con repeat
respuesta <- ""
repeat {
  respuesta <- readline("Escribe algo (o 'salir' para terminar): ")
  print(paste("Has escrito:", respuesta))
  
  if (respuesta == "salir") {
    break
  }
}

Ejemplo: Búsqueda iterativa

Un caso práctico donde los bucles condicionales brillan es en algoritmos de búsqueda o aproximación:

# Encontrar la raíz cuadrada de 25 mediante aproximaciones sucesivas
objetivo <- 25
estimacion <- 1
tolerancia <- 0.0001

while (abs((estimacion * estimacion) - objetivo) > tolerancia) {
  # Fórmula de aproximación de Newton-Raphson
  estimacion <- (estimacion + objetivo/estimacion) / 2
  print(paste("Aproximación actual:", estimacion))
}

print(paste("Raíz cuadrada aproximada de", objetivo, "es", estimacion))
print(paste("Valor real:", sqrt(objetivo)))

Este algoritmo encuentra la raíz cuadrada de un número mediante aproximaciones sucesivas, mejorando la estimación en cada iteración hasta alcanzar la precisión deseada.

Cuándo usar bucles condicionales vs. for

En R, es importante saber cuándo usar cada tipo de bucle:

  • Usa for cuando conoces exactamente cuántas iteraciones necesitas
  • Usa while cuando la iteración depende de una condición que se evalúa al inicio
  • Usa repeat cuando necesitas ejecutar código al menos una vez y la condición de salida se determina dentro del bucle
# Procesamiento de datos con validación
datos <- c(5, 8, NA, 12, -3, NA, 7)
indice <- 1

# Buscar el primer valor válido mayor que 10
while (indice <= length(datos)) {
  valor <- datos[indice]
  
  if (!is.na(valor) && valor > 10) {
    print(paste("Primer valor válido mayor que 10:", valor))
    print(paste("Encontrado en la posición:", indice))
    break
  }
  
  indice <- indice + 1
}

if (indice > length(datos)) {
  print("No se encontró ningún valor que cumpla el criterio")
}

Este ejemplo muestra cómo usar un bucle while para buscar un elemento que cumpla ciertos criterios, algo que sería menos natural con un bucle for.

Vectorización como alternativa a bucles

La vectorización es uno de los conceptos más importantes para programar eficientemente en R. A diferencia de otros lenguajes de programación, R está diseñado para trabajar con vectores completos en lugar de elementos individuales, lo que permite realizar operaciones sobre todos los elementos de un vector simultáneamente sin necesidad de bucles explícitos.

¿Qué es la vectorización?

La vectorización consiste en aplicar operaciones a vectores enteros en lugar de iterar sobre cada elemento. Esta aproximación no solo hace que el código sea más conciso y legible, sino que también resulta significativamente más eficiente en R.

# Enfoque con bucle
numeros <- 1:1000
resultado_bucle <- numeric(1000)

for (i in 1:1000) {
  resultado_bucle[i] <- numeros[i] * 2
}

# Enfoque vectorizado
resultado_vectorizado <- numeros * 2

El enfoque vectorizado es mucho más rápido y requiere menos código.

Operaciones aritméticas vectorizadas

Las operaciones aritméticas básicas en R están vectorizadas por defecto:

# Crear vectores
x <- c(1, 2, 3, 4, 5)
y <- c(10, 20, 30, 40, 50)

# Operaciones vectorizadas
suma <- x + y        # c(11, 22, 33, 44, 55)
resta <- y - x       # c(9, 18, 27, 36, 45)
producto <- x * y    # c(10, 40, 90, 160, 250)
division <- y / x    # c(10, 10, 10, 10, 10)
potencia <- x ^ 2    # c(1, 4, 9, 16, 25)

Cada operación se aplica elemento a elemento sin necesidad de escribir un bucle.

Reciclaje de vectores

R tiene una característica llamada reciclaje de vectores que permite operar con vectores de diferentes longitudes:

# Vector y escalar
numeros <- c(2, 4, 6, 8, 10)
resultado <- numeros * 3  # c(6, 12, 18, 24, 30)

# Vectores de diferentes longitudes
v1 <- c(1, 2, 3, 4, 5)
v2 <- c(10, 20)
resultado <- v1 * v2  # c(10, 40, 30, 80, 50)

En el segundo ejemplo, R recicla v2 para que coincida con la longitud de v1, convirtiéndolo efectivamente en c(10, 20, 10, 20, 10).

Funciones vectorizadas en R

R proporciona numerosas funciones que operan de forma vectorizada:

numeros <- c(-2, -1, 0, 1, 2)

# Funciones matemáticas
abs_valores <- abs(numeros)      # c(2, 1, 0, 1, 2)
raices <- sqrt(abs_valores)      # c(1.414, 1, 0, 1, 1.414)
exponencial <- exp(numeros)      # e elevado a cada valor

# Funciones estadísticas
media <- mean(numeros)           # -0
desviacion <- sd(numeros)        # 1.581139

Estas funciones procesan todos los elementos del vector en una sola operación.

Operaciones lógicas vectorizadas

Las comparaciones y operaciones lógicas también están vectorizadas:

edades <- c(15, 25, 42, 18, 80, 65)

# Comparaciones
mayores_edad <- edades >= 18     # c(FALSE, TRUE, TRUE, TRUE, TRUE, TRUE)
tercera_edad <- edades >= 65     # c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE)

# Operaciones lógicas
adultos_activos <- edades >= 18 & edades < 65  # c(FALSE, TRUE, TRUE, TRUE, FALSE, FALSE)

# Contar elementos que cumplen una condición
num_mayores <- sum(mayores_edad)  # 5 (TRUE se convierte en 1, FALSE en 0)

Estas operaciones permiten filtrar y analizar datos de forma eficiente.

Reemplazando bucles con funciones vectorizadas

Veamos algunos ejemplos de cómo reemplazar bucles comunes con operaciones vectorizadas:

Ejemplo 1: Transformación de datos

# Con bucle
temperaturas_f <- c(32, 50, 68, 86, 104)
temperaturas_c <- numeric(length(temperaturas_f))

for (i in 1:length(temperaturas_f)) {
  temperaturas_c[i] <- (temperaturas_f[i] - 32) * 5/9
}

# Vectorizado
temperaturas_c <- (temperaturas_f - 32) * 5/9

Ejemplo 2: Filtrado de datos

# Con bucle
notas <- c(85, 92, 78, 65, 98, 59, 72)
aprobados <- numeric(0)

for (nota in notas) {
  if (nota >= 70) {
    aprobados <- c(aprobados, nota)
  }
}

# Vectorizado
aprobados <- notas[notas >= 70]

Ejemplo 3: Cálculos acumulativos

# Con bucle
valores <- 1:10
suma_acumulativa <- numeric(length(valores))
suma_acumulativa[1] <- valores[1]

for (i in 2:length(valores)) {
  suma_acumulativa[i] <- suma_acumulativa[i-1] + valores[i]
}

# Vectorizado
suma_acumulativa <- cumsum(valores)

Funciones vectorizadas útiles

R ofrece muchas funciones vectorizadas que pueden reemplazar bucles comunes:

numeros <- c(3, 8, 2, 5, 9, 1)

# Funciones de resumen
suma <- sum(numeros)                # 28
maximo <- max(numeros)              # 9
minimo <- min(numeros)              # 1

# Funciones acumulativas
suma_acumulada <- cumsum(numeros)   # c(3, 11, 13, 18, 27, 28)
prod_acumulado <- cumprod(numeros)  # c(3, 24, 48, 240, 2160, 2160)
maximos <- cummax(numeros)          # c(3, 8, 8, 8, 9, 9)
minimos <- cummin(numeros)          # c(3, 3, 2, 2, 2, 1)

# Funciones de posición
posicion_max <- which.max(numeros)  # 5 (posición del valor máximo)
posicion_min <- which.min(numeros)  # 6 (posición del valor mínimo)

Operaciones con matrices vectorizadas

La vectorización también funciona con matrices:

# Crear una matriz
matriz <- matrix(1:9, nrow = 3)

# Operaciones vectorizadas con matrices
matriz_doble <- matriz * 2
matriz_cuadrado <- matriz^2

# Funciones aplicadas a toda la matriz
suma_total <- sum(matriz)
media_matriz <- mean(matriz)

# Funciones por filas o columnas
sumas_filas <- rowSums(matriz)
medias_columnas <- colMeans(matriz)

Rendimiento: vectorización vs. bucles

La diferencia de rendimiento entre código vectorizado y bucles puede ser sustancial:

# Crear un vector grande
n <- 1000000
x <- rnorm(n)

# Medir tiempo con bucle
tiempo_inicio <- Sys.time()
resultado_bucle <- numeric(n)
for (i in 1:n) {
  resultado_bucle[i] <- x[i]^2
}
tiempo_bucle <- Sys.time() - tiempo_inicio

# Medir tiempo con vectorización
tiempo_inicio <- Sys.time()
resultado_vectorizado <- x^2
tiempo_vectorizado <- Sys.time() - tiempo_inicio

# Comparar tiempos
print(paste("Tiempo con bucle:", tiempo_bucle))
print(paste("Tiempo vectorizado:", tiempo_vectorizado))
print(paste("Veces más rápido:", as.numeric(tiempo_bucle)/as.numeric(tiempo_vectorizado)))

En este ejemplo, la versión vectorizada puede ser decenas o incluso cientos de veces más rápida.

Cuándo usar vectorización vs. bucles

Aunque la vectorización es generalmente preferible en R, hay situaciones donde los bucles siguen siendo útiles:

  • Cuando cada iteración depende del resultado de iteraciones anteriores
  • En algoritmos que no pueden expresarse fácilmente de forma vectorizada
  • Para operaciones muy complejas donde la claridad del código es prioritaria
# Ejemplo: secuencia de Fibonacci (difícil de vectorizar)
fibonacci <- numeric(10)
fibonacci[1] <- 1
fibonacci[2] <- 1

for (i in 3:10) {
  fibonacci[i] <- fibonacci[i-1] + fibonacci[i-2]
}

Ejemplo práctico: análisis de datos meteorológicos

Veamos un ejemplo completo que muestra el poder de la vectorización:

# Temperaturas diarias (°C) durante dos semanas
temperaturas <- c(22, 24, 19, 21, 25, 26, 28, 27, 23, 20, 19, 22, 24, 26)

# Análisis vectorizado
media_temp <- mean(temperaturas)
dias_calurosos <- sum(temperaturas > 25)
amplitud_termica <- max(temperaturas) - min(temperaturas)

# Convertir a Fahrenheit (vectorizado)
temp_fahrenheit <- (temperaturas * 9/5) + 32

# Identificar cambios de temperatura
cambios <- diff(temperaturas)  # diferencias entre días consecutivos
dias_aumento <- sum(cambios > 0)
dias_descenso <- sum(cambios < 0)

# Resultados
print(paste("Temperatura media:", round(media_temp, 1), "°C"))
print(paste("Días con más de 25°C:", dias_calurosos))
print(paste("Amplitud térmica:", amplitud_termica, "°C"))
print(paste("Días con aumento de temperatura:", dias_aumento))
print(paste("Días con descenso de temperatura:", dias_descenso))

Este análisis completo se realiza sin un solo bucle, demostrando la potencia y elegancia de la programación vectorizada en R.

Aprende R online

Otros ejercicios de programación de R

Evalúa tus conocimientos de esta lección Estructuras de control iterativo con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de R

Accede a todas las lecciones de R y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Instalación De R Y Rstudio

R

Introducción Y Entorno

Introducción A R

R

Introducción Y Entorno

Operadores

R

Sintaxis

Estructuras De Datos

R

Sintaxis

Funciones

R

Sintaxis

Estructuras De Control Iterativo

R

Sintaxis

Scopes Y Closures

R

Sintaxis

Estructuras De Control Condicional

R

Sintaxis

Funciones Anónimas

R

Sintaxis

Tipos De Datos Y Variables

R

Sintaxis

Sistema R6: Clases Referenciales Y Encapsulamiento

R

Programación Orientada A Objetos

Sistema S4: Clases Formales Y Validación

R

Programación Orientada A Objetos

Herencia Y Polimorfismo En R

R

Programación Orientada A Objetos

Sistemas De Oop En R

R

Programación Orientada A Objetos

Sistema S3: Clases Implícitas Y Métodos Genéricos

R

Programación Orientada A Objetos

Tidyverse Para Transformación De Datos

R

Manipulación De Datos

Lubridate Para Fechas Y Tiempo

R

Manipulación De Datos

Group_by Y Summarize Para Agrupación Y Resumen

R

Manipulación De Datos

Stringr Para Expresiones Regulares

R

Manipulación De Datos

Tidyr Para Limpieza De Valores Faltantes

R

Manipulación De Datos

Joins En R Para Combinación Y Relaciones De Tablas

R

Manipulación De Datos

Pivot_longer Y Pivot_wider Para Reestructuración

R

Manipulación De Datos

Mutate Y Transmute Para Transformación

R

Manipulación De Datos

Dplyr Para Filtrado Y Selección

R

Manipulación De Datos

Readr Y Read.csv Para Importar Datos

R

Manipulación De Datos

Gráficos Bivariantes En R

R

Visualización De Datos

Gráficos Univariantes En R

R

Visualización De Datos

Facetas En Ggplot2

R

Visualización De Datos

Personalización Y Temas

R

Visualización De Datos

Ggplot2 Para Visualización De Datos

R

Visualización De Datos

Gráficos Multivariantes En R

R

Visualización De Datos

Correlación En R

R

Estadística

Regresión Lineal En R

R

Estadística

Pruebas De Hipótesis En R

R

Estadística

Anova En R

R

Estadística

Estadística Descriptiva En R

R

Estadística

Accede GRATIS a R y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender la sintaxis y uso básico de los bucles for para iterar sobre vectores, secuencias y matrices.
  • Aprender a utilizar bucles while y repeat para iteraciones condicionales y controladas por condiciones.
  • Conocer el uso de las instrucciones break y next para controlar el flujo dentro de los bucles.
  • Entender el concepto de vectorización en R y cómo reemplaza bucles para mejorar la eficiencia.
  • Aplicar técnicas de iteración y vectorización en ejemplos prácticos de análisis de datos.