5.2 Control de flujo
En R existen algunos operadores para controlar el flujo de las acciones a tomar en la ejecución. Esto sucede solamente cuando se cumple una condición dada. Recordemos que las condiciones lógicas se resuelven como verdadera TRUE
o falsa FALSE
. Existen operadores de elección (if
, else
) y de iteración o loop (for
, while
). Se revisará a detalle sus usos en las siguientes secciones.

Figura 5.2: Diagramas de flujo para comprender cómo funcionan las principales estructuras de control de flujo en programación con R.
5.2.1 Control con if
El primer operador de control de flujo a destacar es el condicional if
. Este significa si
, y ejecuta la expresión: si A se cumple (es decir, si A es TRUE
), muestro un resultado. Este tienen la estructura básica:
if (condición) acción_si_la_condición_es_verdadera
Ejemplo 5.5 Para poner en contexto lo anterior:
### Crear una condición verdadera
<- TRUE
condicion
if(condicion) 1
# [1] 1
En este sentido,if
mostrará como resultado lo que esté a la derecha del paréntesis de condición, siempre y cuando la condición sea verdadera. Cuando la condición es falsa, no muestra resultado alguno:
### Crear una condición falsa
<- FALSE
condicion
if (condicion) 1
Ejemplo 5.6 En la siguiente expresión, reemplazaremos la condición TRUE
por una condición real con un vector llamado num
. Se hará la pregunta lógica ¿es el objeto num
numeric?. El resultado será un texto indicando que num
es un número siempre que la condición sea verdadera.
### Cuando num es un número
<- 123
num
if (is.numeric(num)) paste(num, "es un número")
# [1] "123 es un número"
### Cuando num no es un número
<- "Andes Tropicales"
num
if (is.numeric(num)) paste(num, "es un número")
En el ejemplo con "Andes Tropicales"
, la condición no fue verdadera, if
no mostró resultado alguno en consola.
5.2.2 Control completo con if
y else
El segundo operador de control que uno debe conocer es else
. Este significa entonces
, y suele colocarse acompañando a if
para completar la condición universal: si A se cumple, muestro un resultado; si A no se cumple, entonces muestro otro resultado. Utilizando ambis, se obtiene tienen la estructura básica:
if (condición) acción_si_la_condición_es_verdadera else acción_si_la_condición_es_falsa
Ejemplo 5.7 Poniendo en contexto lo mencionado:
### Usar if y else con una condición lógica
<- TRUE
condicion
if (condicion) 1 else 0
# [1] 1
### Usar if y else con una condición lógica
<- FALSE
condicion
if (condicion) 1 else 0
# [1] 0
Es más frecuente utilizar llaves {}
para definir el resultado de if
o el otro resultado de else
:
### Usar if y else con una condición lógica
<- TRUE
condicion
if (condicion) {1} else {0}
# [1] 1
### Usar if y else con una condición lógica
<- FALSE
condicion
if (condicion) {1} else {0}
# [1] 0
Para escribir un código con varias líneas de if
y else
, es necesario respetar el sangrado (espacio desde el borde), siendo que else
se muestre sangrado dentro de la cadena de código iniciada con if
.
### Código de if y else en varias líneas
<- FALSE
condicion
if (condicion) {
1
else {
} 0}
# [1] 0
Ejemplo 5.8 Veamos una aplicación más completa de todo lo discutido hasta el momento:
### Cuando num es un número
<- 123
num
if (is.numeric(num)) {
paste(num, "es un número")
else {
} paste(num, "no es un número")
}# [1] "123 es un número"
### Cuando num no es un número
<- "Andes Tropicales"
num
if (is.numeric(num)) {
paste(num, "es un número")
else {
} paste(num, "no es un número")
}# [1] "Andes Tropicales no es un número"
Ejemplo 5.9 A continuación varias aplicaciones para identificar si un valor numérico es par o impar, para identificar si un valor es NA, y para identificar si un valor es del tipo carácter o texto:
### Con valor numérico para identificar par o impar
<- 120
valor
if((valor %% 2) == 0) {
print(paste(valor,"es par"))
else if ((valor %% 2) != 0) {
} print(paste(valor,"es impar"))
}# [1] "120 es par"
### Con valor NA para identificar si es NA o un texto
<- NA
valor
if (is.na(valor)) {
print(paste(valor, "es un valor perdido"))
else {
} print(paste(valor, "no es un valor perdido, debe ser un texto"))
}# [1] "NA es un valor perdido"
### Con valor NA para identificar si es NA o un texto
<- "América"
valor
if (is.na(valor)) {
print(paste(valor, "es un valor perdido"))
else {
} print(paste(valor, "no es un valor perdido, debe ser un texto"))
}# [1] "América no es un valor perdido, debe ser un texto"
Ejemplo 5.10 Crear un proceso complejo que involucre una respuesta para cualquiera de los tipos de elementos ofrecidos en el ejemplo anterior (valor numérico, NA y textual) puede ser un dolor de cabeza. Si se concatenan las condiciones con else
e if
de manera errada, generará un error:
### Forma errada
<- "Mil quinientos veinte"
valor
if((valor %% 2) == 0) {
print(paste(valor,"es par"))
else if ((valor %% 2) != 0) {
} print(paste(valor,"es impar"))
else if (is.na(valor)) {
} print(paste(valor, "es un valor perdido"))
else {
} print(paste(valor, "no es un valor perdido, debe ser un texto"))
}# Error in valor%%2 : non-numeric argument to binary operator
La manera correcta de crear esta condición compleja se obtiene primero preguntando si el elemento valor
es número o no. Este paso es fundamental debido a las limitaciones razonables de operar numéricamente con %%
un texto, generando un error:
"Mil quinientos veinte" %% 2
# Error in "Texto"%%2 : non-numeric argument to binary operator
Incluyendo la pregunta ¿es verdad TRUE
que el valor es un número? con is.numeric(valor) == TRUE
para cuando valor es número; y la pregunta ¿es falso FALSE
que el valor es un número? con is.numeric(valor) == FALSE
, para cuando valor es texto:
### Tómate el tiempo que necesites para
### entender cómo funciona esta estructura
### Prueba su aplicación cambiando el contenido de valor:
<- "Mil quinientos veinte"
valor
if (is.numeric(valor) == TRUE) {
if((valor %% 2) == 0) {
print(paste(valor,"es par"))
else if ((valor %% 2) != 0) {
} print(paste(valor,"es impar"))
}else if (is.numeric(valor) == FALSE) {
} if (is.na(valor)) {
print(paste(valor, "es un valor perdido"))
else {
} print(paste(valor, "no es un valor perdido, debe ser un texto"))
}
}# [1] "Mil quinientos veinte no es un valor perdido, debe ser un texto"
if
como else
permiten evaluar elementos dentro de una función y pueden funcionar como interruptores que de decanten en la elección de una ruta de análisis en relación a una condición relacionada con el elemento u objeto de entrada.
Para entender la importancia de estos interruptores en la creación de funciones, revisemos el contenido de la función dist()
, que calcula una matriz de distancias para análisis multivariados. Para esta función, es importante especificar qué método de cálculo de distancias se debe usar. Siempre existirá alguno definido por defecto, en este caso "euclidean"
(distancia euclidiana). Reconoce las estructuras if
y else
que usa la función para decidir qué hacer cuando se le a otorgado uno u otro valor en el argumento method
.
dist# function (x, method = "euclidean", diag = FALSE, upper = FALSE,
# p = 2)
# {
# if (!is.na(pmatch(method, "euclidian")))
# method <- "euclidean"
# METHODS <- c("euclidean", "maximum", "manhattan", "canberra",
# "binary", "minkowski")
# method <- pmatch(method, METHODS)
# if (is.na(method))
# stop("invalid distance method")
# if (method == -1)
# stop("ambiguous distance method")
# x <- as.matrix(x)
# N <- nrow(x)
# attrs <- if (method == 6L)
# list(Size = N, Labels = dimnames(x)[[1L]], Diag = diag,
# Upper = upper, method = METHODS[method], p = p, call = match.call(),
# class = "dist")
# else list(Size = N, Labels = dimnames(x)[[1L]], Diag = diag,
# Upper = upper, method = METHODS[method], call = match.call(),
# class = "dist")
# .Call(C_Cdist, x, method, attrs, p)
# }
# <bytecode: 0x000001451075c7c0>
# <environment: namespace:stats>
5.2.3 Condicionales en vectores de más de un elemento con ifelse()
De manera similar al uso de if
y else
, es posible operar de manera vectorial. Esto significa: aplicar una condición a cada elemento de un vector, para que cuando esta se cumpla (sea TRUE
) se de un resultado, mientras que otorgue otro cuando no se cumpla (sea FALSE
). La función ifelse()
, encargada de ello, requiere como argumentos una condición lógica, un valor para cuando la condición sea TRUE
y otro valor para cuando sea FALSE
. La estructura básica es:
ifelse(condicion, "acción_si_la_condición_es_verdadera", "acción_si_la_condición_es_falsa")
Ejemplo 5.11 Usando ifelse()
para identificar los valores pares e impares de un vector numérico:
### Crear un vector cualquiera
<- 1:50
vector
### Usar ifelse()
ifelse((vector %% 2) == 0, "Par", "Impar")
# [1] "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par"
# [11] "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par"
# [21] "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par"
# [31] "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par"
# [41] "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par" "Impar" "Par"
Es posible incluir una función ifelse()
dentro de otra en la posición de resultado FALSE
para concatenar varias condiciones aplicadas al mismo vector:
### Usar ifelse()
ifelse((vector %% 2) == 0 & vector > 10, "Par >10",
ifelse((vector %% 2) == 0 & vector <= 10, "Par <=10",
ifelse((vector %% 2) != 0 & vector > 10, "impar >10", "impar <=10")))
# [1] "impar <=10" "Par <=10" "impar <=10" "Par <=10" "impar <=10" "Par <=10"
# [7] "impar <=10" "Par <=10" "impar <=10" "Par <=10" "impar >10" "Par >10"
# [13] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [19] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [25] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [31] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [37] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [43] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [49] "impar >10" "Par >10"
5.2.4 Condicionales en vectores case_when()
de dplyr
La función case_when()
de la librería dplyr es la solución para cuando se necesita utilizar muchos ifelse()
concatenados. Su uso, como otras funciones de dplyr, es sencillo. La estructura básica es:
case_when(
~ "resultado_verdadero",
condicion ~ "resultado_verdadero",
condicion ~ "resultado_verdadero",
condicion ~ "resultado_verdadero"
condicion )
Ejemplo 5.12 Resolviendo el último ejemplo de la sección anterior con case_when()
:
### Crear un vector
<- 1:50
vector
### Evaluar el vector con case_when()
library(dplyr)
case_when(
%% 2) == 0 & vector > 10 ~ "Par >10",
(vector %% 2) == 0 & vector <= 10 ~ "Par <=10",
(vector %% 2) != 0 & vector > 10 ~ "impar >10",
(vector %% 2) != 0 & vector <= 10 ~ "impar <=10"
(vector
)# [1] "impar <=10" "Par <=10" "impar <=10" "Par <=10" "impar <=10" "Par <=10"
# [7] "impar <=10" "Par <=10" "impar <=10" "Par <=10" "impar >10" "Par >10"
# [13] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [19] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [25] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [31] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [37] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [43] "impar >10" "Par >10" "impar >10" "Par >10" "impar >10" "Par >10"
# [49] "impar >10" "Par >10"
Cuando hay elementos que no cumplen con ninguna condición ofrecida, el elemento se reemplaza por NA
en el vector de resultado:
### Crear un vector
<- 1:50
vector
### Evaluar el vector con case_when()
### con una sola condición
library(dplyr)
case_when(
%% 2) == 0 & vector > 10 ~ "Par >10"
(vector
)# [1] NA NA NA NA NA NA NA NA
# [9] NA NA NA "Par >10" NA "Par >10" NA "Par >10"
# [17] NA "Par >10" NA "Par >10" NA "Par >10" NA "Par >10"
# [25] NA "Par >10" NA "Par >10" NA "Par >10" NA "Par >10"
# [33] NA "Par >10" NA "Par >10" NA "Par >10" NA "Par >10"
# [41] NA "Par >10" NA "Par >10" NA "Par >10" NA "Par >10"
# [49] NA "Par >10"
5.2.5 Ciclos o Loops con for
El segundo grupo de operadores de control de flujo incluye a los responsables de ciclos, iteraciones o loops. Un loop con for
tienen la siguiente estructura básica:
for (elemento in vector_secuencial) {acciones a realizar}
5.2.5.1 Entendiendo la estructura básica de for
Elemento
y vector_secuencial
son dos cosas que no se han visto hasta el momento. Elemento se comporta como una variable de posición. Es clásico que se coloque a i
como elemento, pero puede ser cualquier letra o palabra, siempre y cuando esta se utilice dentro del loop. El elemento funciona como variable de posición, y en cada vuelta del loop, i
será reemplazado con un elemento del vector_secuencial
, uno a uno en orden correlativo.
El vector_secuencial
, por su parte, es un vector que debe contener la secuencia correlativa de números que vaya desde 1 hasta la cantidad máxima de elementos que tiene el vector sobre el que se pretende aplicar el loop. Si el vector inicial al que se le aplicará el loop contiene solo cuatro elementos: c(10.1, 50.9, 23.4, 31.5)
, se debe colocar una de las siguientes opciones dentro del paréntesis de for
:
### Vector sobre el que aplicar el loop
<- c(10.1, 50.9, 23.4, 31.5) vector
### Opción 1: colocar un rango manualmente (poco eficiente)
for (i in 1:4)
### Opción 1: colocar un rango con length() (no recomendado)
for (i in 1:length(vector))
### Opción 1: usando seq_along() para crear el rango (recomendado)
for (i in seq_along(vector))
5.2.5.2 Uso de for
Ejemplo 5.13 Utilizando un loop para obtener solo los valores mayores igual al promedio de un conjunto de datos:
### Crear aleatoriamente un conjunto de datos
### que siga la distribución normal
set.seed(123)
<- rnorm(200, mean = 20, sd=5.6)
aleatorio
### Crear un objeto vacío para rellenarlo
### con el resultado de cada vuelta del loop
<- c()
res
### Loop sin importar que se generen NA
for (i in seq_along(aleatorio)){
if (aleatorio[i] >= mean(aleatorio)) {
<- aleatorio[i]
res[i]
}
}
### Resultado
res# [1] NA NA 28.73 20.39 20.72 29.60 22.58 NA NA NA 26.85 22.01 22.24
# [14] 20.62 NA 30.01 22.79 NA 23.93 NA NA NA NA NA NA NA
# [27] 24.69 20.86 NA 27.02 22.39 NA 25.01 24.92 24.60 23.86 23.10 NA NA
# [40] NA NA NA NA 32.15 26.76 NA NA NA 24.37 NA 21.42 NA
# [53] NA 27.66 NA 28.49 NA 23.27 20.69 21.21 22.13 NA NA NA NA
# [66] 21.70 22.51 20.30 25.16 31.48 NA NA 25.63 NA NA 25.74 NA NA
# [79] 21.02 NA 20.03 22.16 NA 23.61 NA 21.86 26.14 22.44 NA 26.43 25.56
# [92] 23.07 21.34 NA 27.62 NA 32.25 28.58 NA NA NA 21.44 NA NA
# [105] NA NA NA NA NA 25.15 NA 23.40 NA NA 22.91 21.69 20.59
# [118] NA NA NA 20.66 NA NA NA 30.33 NA 21.32 20.44 NA NA
# [131] 28.09 22.53 20.23 NA NA 26.34 NA 24.14 30.69 NA 23.93 NA NA
# [144] NA NA NA NA 23.85 31.76 NA 24.41 24.31 21.86 NA NA NA
# [157] 23.15 NA 25.47 NA 25.90 NA NA 38.15 NA 21.67 23.56 NA 22.89
# [170] 22.07 NA 20.37 NA 31.92 NA NA 20.21 21.74 22.44 NA NA 27.07
# [183] NA NA NA NA 26.22 20.47 24.22 NA 21.20 NA 20.53 NA NA
# [196] 31.18 23.36
Para no generar NA
en el resultado se usa un truco: ir adicionando el resultado a res
como un vector que concatena el contenido de hasta la iteración anterior de res
, más el contenido de la iteración actual:
### Loop sin NA
<- c()
res for (i in seq_along(aleatorio)){
if (aleatorio[i] >= mean(aleatorio)) {
<- c(res, aleatorio[i]) # aquí está el truco
res
}
}
### Resultado
res# [1] 28.73 20.39 20.72 29.60 22.58 26.85 22.01 22.24 20.62 30.01 22.79 23.93 24.69
# [14] 20.86 27.02 22.39 25.01 24.92 24.60 23.86 23.10 32.15 26.76 24.37 21.42 27.66
# [27] 28.49 23.27 20.69 21.21 22.13 21.70 22.51 20.30 25.16 31.48 25.63 25.74 21.02
# [40] 20.03 22.16 23.61 21.86 26.14 22.44 26.43 25.56 23.07 21.34 27.62 32.25 28.58
# [53] 21.44 25.15 23.40 22.91 21.69 20.59 20.66 30.33 21.32 20.44 28.09 22.53 20.23
# [66] 26.34 24.14 30.69 23.93 23.85 31.76 24.41 24.31 21.86 23.15 25.47 25.90 38.15
# [79] 21.67 23.56 22.89 22.07 20.37 31.92 20.21 21.74 22.44 27.07 26.22 20.47 24.22
# [92] 21.20 20.53 31.18 23.36
Ejemplo 5.14 Otra manera de conseguir el efecto visto en el ejemplo anterio es utilizando el operador condicional next
. Este “salta” un ciclo cuando se cumple la condición del if
previo. Nota como la condición en if
pide lo contrario a lo que se necesita, para que cuando se cumpla se active next
y cuando no se cumpla se guarda el valor concatenado en res.
### Crear un objeto vacío
<- c()
res
### Loop con next y condición if inversa a lo requerido
for (i in seq_along(aleatorio)){
if (aleatorio[i] < mean(aleatorio)) # condición inversa para usar next
next
<- c(res, aleatorio[i])
res
}
### Resultado
res# [1] 28.73 20.39 20.72 29.60 22.58 26.85 22.01 22.24 20.62 30.01 22.79 23.93 24.69
# [14] 20.86 27.02 22.39 25.01 24.92 24.60 23.86 23.10 32.15 26.76 24.37 21.42 27.66
# [27] 28.49 23.27 20.69 21.21 22.13 21.70 22.51 20.30 25.16 31.48 25.63 25.74 21.02
# [40] 20.03 22.16 23.61 21.86 26.14 22.44 26.43 25.56 23.07 21.34 27.62 32.25 28.58
# [53] 21.44 25.15 23.40 22.91 21.69 20.59 20.66 30.33 21.32 20.44 28.09 22.53 20.23
# [66] 26.34 24.14 30.69 23.93 23.85 31.76 24.41 24.31 21.86 23.15 25.47 25.90 38.15
# [79] 21.67 23.56 22.89 22.07 20.37 31.92 20.21 21.74 22.44 27.07 26.22 20.47 24.22
# [92] 21.20 20.53 31.18 23.36
Ejemplo 5.15 Si es requerido frenar el loop antes de que culmine, en base a una nueva condición definida, se debe utilizar break
. En nuestro ejemplo, para frenar el loop cuando aparezca el primer valor mayor a 30.5, es necesario ir evaluando en cada iteración del loop si existe al menos un valor > 30.5
en el objeto res
. Esto se obtiene con any(res > 30.5)
. En el momento que se cumpla, break
frena el loop.
### Crear un objeto vacío
<- c()
res
### Loop con next y condición if inversa a lo requerido
for (i in seq_along(aleatorio)){
if (aleatorio[i] < mean(aleatorio))
next
<- c(res, aleatorio[i])
res
if (any(res > 30.5)) # hay que evaluar si hay algún (any)
break
}
### Resultado
res# [1] 28.73 20.39 20.72 29.60 22.58 26.85 22.01 22.24 20.62 30.01 22.79 23.93 24.69
# [14] 20.86 27.02 22.39 25.01 24.92 24.60 23.86 23.10 32.15
5.2.6 Ciclos o loops con replicate()
La función replicate()
facilita mucho procesos iterativos para simulación. Permite replicar una o varias líneas de código las veces que sean definidas, para almacenarlas como una lista de vectores (con el argumento simplify = FALSE
), o como un vector único (con el argumento simplify = TRUE
, como está por defecto). Ejemplificaremos su uso con un caso de estudio:
Ejemplo 5.16 Se ha evaluado una población, de la cual se obtuvo como muestra 100 medidas de una longitud. Al obtener el valor más grande de dicha muestra se obtiene:
### Valores del estudio
<- c(155.62, 158.5, 174.06, 161.11, 161.62, 175.42, 164.51, 149.49,
muestra 154.52, 156.62, 171.15, 163.63, 163.99, 161.46, 155.66, 176.05,
164.83, 143.39, 166.6, 156.39, 151.21, 158.6, 151.57, 154.16,
155.06, 145.83, 167.79, 161.83, 150.6, 171.41, 164.21, 157.93,
168.29, 168.14, 167.65, 166.49, 165.32, 159.96, 157.84, 157.19,
154.46, 158.69, 149.49, 179.37, 171.01, 150.73, 156.99, 156.44,
167.29, 159.77, 162.7, 160.25, 160.13, 172.41, 158.54, 173.69,
147.03, 165.59, 161.58, 162.38, 163.8, 156.13, 157.6, 151.64,
151.18, 163.14, 164.4, 160.96, 168.52, 178.34, 156.23, 140.41,
169.25, 154.33, 154.51, 169.42, 158.02, 149.88, 162.08, 159.29,
160.55, 163.85, 157.28, 166.11, 158.58, 163.39, 170.04, 164.29,
157.66, 170.49, 169.14, 165.27, 162.58, 155.04, 172.34, 155.28,
179.53, 173.83, 158.45, 151.57)
### El valor más alto de dicha población
max(muestra)
# [1] 179.5
Pero ¿Siempre será así?. ¿Será que si evaluo nuevamente la población obtendré el mismo valor máximo?. Como no tenemos dinero ni tiempo para volver a evaluar dicha población, decidimos simularla. En este paso necesitamos información de la muestra:
### Promedio
<- mean(muestra)
promedio
### Desviación estándar
<- sd(muestra) desvest
Con estos datos se puede simular una población en R. Asumiendo que esta siguen una distribución normal, utilizamos:
### Simular los datos
set.seed(123)
<- rnorm(100, mean = promedio, sd = desvest)
muestra_simulada
### Ver los resultados
muestra_simulada# [1] 156.8 159.5 173.7 161.8 162.3 174.9 164.9 151.2 155.8 157.7 171.0 164.1 164.5
# [14] 162.2 156.9 175.5 165.2 145.7 166.9 157.5 152.8 159.6 153.1 155.5 156.3 147.9
# [27] 167.9 162.5 152.2 171.2 164.7 158.9 168.4 168.3 167.8 166.8 165.7 160.8 158.9
# [40] 158.3 155.8 159.6 151.2 178.5 170.9 152.4 158.1 157.6 167.5 160.6 163.3 161.1
# [53] 160.9 172.2 159.5 173.3 149.0 165.9 162.3 163.0 164.3 157.3 158.6 153.2 152.8
# [66] 163.7 164.8 161.7 168.6 177.6 157.4 142.9 169.3 155.7 155.8 169.4 159.0 151.6
# [79] 162.7 160.2 161.3 164.3 158.3 166.4 159.5 163.9 170.0 164.7 158.7 170.4 169.2
# [92] 165.6 163.2 156.3 172.1 156.5 178.7 173.5 159.4 153.1
Para repetir esta simulación diez mil veces, y obtener estadísticos descriptivos de los valores máximos de dichas muchas simuladas, utilizaremos replicate()
con dos pasos internos por cada iteración del loop:
- Crear un conjunto de números aleatorios para la iteración.
- Hallar el valor máximo de la longitud en dicho conjunto.
### Usar replicate()
set.seed(123)
<- replicate(n = 10000, {
resultados <- rnorm(100, mean = promedio, sd = desvest)
parcial max(parcial)
}
)
### Revisar el valor máximo, mínimo y promedio de longitudes
### máximas obtenidas por el loop de replicate()
min(resultados)
# [1] 171.8
max(resultados)
# [1] 199.8
mean(resultados)
# [1] 181.2
### Valor máximo de la muestra original
max(muestra)
# [1] 179.5
Con ello nos hemos dado cuenta que, asumiendo que la variable tiene distribución de probabilidades normal, el valor máximo de la muestra original (179.53), es menor al promedio poblacional simulado con diez mil réplicas (199.809). Por el contrario, está más cerca del valor máximo más pequeño dentro de los diez mil datos (171.7636).
5.2.7 Ciclos o Loops con while
Otro operador de control de flujo con el que se crea loops es while
. A diferencia de for
, que opera hasta que se acaben las iteraciones definidas por el rango 1:n
, while
se detendrá solo hasta que se cumpla una condición. Si dicha condición nunca se cumple, se crea un loop infinito. Un loop con while
tienen la siguiente estructura básica:
# Posición inicial
<- 1
index
# Loop con while
while (condicion_respecto_a_index) {
acciones a realizar<- index + 1
index }
Es la segunda línea de la condición a realizar dentro del loop while
lo que le da la continuidad. En alguna iteración, el ir “sumando” valores al index hará que se cumpla la condición definida.
Ejemplo 5.17 Veamos su aplicación:
# Posición inicial
<- 1
index
# Loop con while
while (index <= 5) {
# Acción a realizar
print(paste("El número es", index))
# Suma una posición para la siguiente iteración
<- index + 1
index
}# [1] "El número es 1"
# [1] "El número es 2"
# [1] "El número es 3"
# [1] "El número es 4"
# [1] "El número es 5"
Una segunda manera de operar es indicar que se frene el loop hasta que una condición lógica cambie de estado (FALSE
a TRUE
, o viceversa).
Ejemplo 5.18 Se aplicará el imprimir la secuencia de bases nitrogenadas (letras A
, C
, G
, T
) hasta que se ubique la primera base G. Trata de interpretar cada paso dentro de una iteración del loop while
:
### Vector sobre el cual hacer la impresión de elementos
<- c("A","T","C","A","T","G","G","G","G","C","C")
vector
### Condición en estado falso
<- FALSE
condicion
### Índice
<- 1
index
### Loop con while
### Aquí !condicion significa:
### "mientras que condición no sea verdadera, continuar"
while ( !condicion ) {
print(vector[index]) # imprime el elemento
<- index + 1 # adiciona una posición
index <- vector[index] == "G" # evalúa si es G la siguiente posición
condicion
}# [1] "A"
# [1] "T"
# [1] "C"
# [1] "A"
# [1] "T"
Intentar con for
lo explicado en el ejemplo anterior llevaría al resultado erróneo de imprimir todo menos los elementos que se soliciten, como “G”:
### Vector sobre el cual hacer la impresión de elementos
<- c("A","T","C","A","G","T","C","A",
vector "T","G","G","C","G","G","C","C")
### Loop con for
for(i in seq_along(vector)){
if(vector[i]!="G")
print(vector[i])
}# [1] "A"
# [1] "T"
# [1] "C"
# [1] "A"
# [1] "T"
# [1] "C"
# [1] "A"
# [1] "T"
# [1] "C"
# [1] "C"
# [1] "C"
Algo más interesante para el loop while
podría ser frenar la impresión de elementos cuando se identifique que a partir de la siguiente iteración aparecerá una secuencia definida.
Ejemplo 5.19 Imagina que necesitas frenar la impresión hasta que aparezca la primera secuencia TGC
, en ese orden:
# Objetos necesarios
<- c("A","T","C","A","G","T","C","A",
vector "T","G","G","C","G","G","C","C")
<- FALSE
condicion <- 1
index
### Loop con while
while ( !condicion ) {
print(vector[index])
<- index + 1
index <- identical(c(vector[index], vector[index+1],
condicion +2]), c("T","G","G"))
vector[index
}# [1] "A"
# [1] "T"
# [1] "C"
# [1] "A"
# [1] "G"
# [1] "T"
# [1] "C"
# [1] "A"