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ícateBucles 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 buclenext
: 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:
- La condición eventualmente se volverá
FALSE
- 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.
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
Introducción Y Entorno
Introducción A R
Introducción Y Entorno
Operadores
Sintaxis
Estructuras De Datos
Sintaxis
Funciones
Sintaxis
Estructuras De Control Iterativo
Sintaxis
Scopes Y Closures
Sintaxis
Estructuras De Control Condicional
Sintaxis
Funciones Anónimas
Sintaxis
Tipos De Datos Y Variables
Sintaxis
Sistema R6: Clases Referenciales Y Encapsulamiento
Programación Orientada A Objetos
Sistema S4: Clases Formales Y Validación
Programación Orientada A Objetos
Herencia Y Polimorfismo En R
Programación Orientada A Objetos
Sistemas De Oop En R
Programación Orientada A Objetos
Sistema S3: Clases Implícitas Y Métodos Genéricos
Programación Orientada A Objetos
Tidyverse Para Transformación De Datos
Manipulación De Datos
Lubridate Para Fechas Y Tiempo
Manipulación De Datos
Group_by Y Summarize Para Agrupación Y Resumen
Manipulación De Datos
Stringr Para Expresiones Regulares
Manipulación De Datos
Tidyr Para Limpieza De Valores Faltantes
Manipulación De Datos
Joins En R Para Combinación Y Relaciones De Tablas
Manipulación De Datos
Pivot_longer Y Pivot_wider Para Reestructuración
Manipulación De Datos
Mutate Y Transmute Para Transformación
Manipulación De Datos
Dplyr Para Filtrado Y Selección
Manipulación De Datos
Readr Y Read.csv Para Importar Datos
Manipulación De Datos
Gráficos Bivariantes En R
Visualización De Datos
Gráficos Univariantes En R
Visualización De Datos
Facetas En Ggplot2
Visualización De Datos
Personalización Y Temas
Visualización De Datos
Ggplot2 Para Visualización De Datos
Visualización De Datos
Gráficos Multivariantes En R
Visualización De Datos
Correlación En R
Estadística
Regresión Lineal En R
Estadística
Pruebas De Hipótesis En R
Estadística
Anova En R
Estadística
Estadística Descriptiva En R
Estadística
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.