Los mensajes de error en el post original se debe al hecho de que d_i$a
y d_i$b
son vectores con 1.000 elementos y 10 es un escalar. Por lo tanto, R compara el primer elemento en d_i$a
y el primer elemento en d_i$b
con 10.
Para resolver el mensaje de error tenemos que comparar un vector con longitud de 1 a escalar 10. Esto requiere reestructurar el código para generar los números aleatorios de una en una. A partir de la descripción en el post original, no está claro si este comportamiento fue intencional.
Voy a simplificar el problema mediante la eliminación de la serie de 10 repeticiones para ilustrar cómo crear un marco de datos con números aleatorios hasta una fila tiene tanto a
y b
con valores mayores que 10.
En primer lugar, realizaremos una semilla para que la respuesta es reproducible, y luego inicializar algunos de los objetos. Mediante el establecimiento de a
y b
a 0 nos aseguramos de que el while()
bucle se ejecutará al menos una vez.
set.seed(950141238) # for reproducibility
results <- list()
a <- 0 # initialize a to a number < 10
b <- 0 # initialize b to a number < 10
i <- 1 # set a counter
De haber inicializado a
y b
el while()
bucle se evalúa a TRUE
genera dos números aleatorios, se le asigna un valor de índice, y escribe como un marco de datos para la results
lista. La lógica de la while()
loop indica que si bien a
es menor o igual a 10 o b
es menor o igual a 10, el bucle mantiene la iteración. Se detiene cuando ambos a
y b
son mayores que 10.
while(a <= 10 | b <= 10){
a <- rnorm(1,10,1) # generate 1 random number with mean of 10 and sd of 1
b <- rnorm(1,10,1) # ditto
results[[i]] <- data.frame(index = i,a,b)
i <- i + 1 # increment i
}
El bucle deja de ejecutarse después de la novena iteración como podemos ver por la impresión de los datos resultantes del marco después de combinar las filas individuales con do.call()
y rbind()
.
df <- do.call(rbind,results)
df
...y el resultado:
> df
index a b
1 1 8.682442 8.846653
2 2 9.204682 8.501692
3 3 8.886819 10.488972
4 4 11.264142 8.952981
5 5 9.900112 10.918042
6 6 9.185120 10.625667
7 7 9.620793 10.316724
8 8 11.718397 9.256835
9 9 10.034793 11.634023
>
Observe que la última fila en el marco de datos tiene valores mayores que 10 para ambos a
y b
.
Múltiples repeticiones del bucle while
Repetir el proceso 10 veces como se hace en el post original, que envuelva la operación en un for()
bucle, y agregar una segunda lista, combined_results
para guardar los resultados de cada iteración.
set.seed(950141238) # for reproducibility
combined_results <- list()
for(iteration in 1:10){
results <- list()
a <- 0 # initialize a to a number < 10
b <- 0 # initialize b to a number < 10
i <- 1 # set a counter
while((a < 10) | (b < 10)){
a <- rnorm(1,10,1) # generate 1 random number with mean of 10 and sd of 1
b <- rnorm(1,10,1) # ditto
results[[i]] <- data.frame(iteration,index = i,a,b)
i <- i + 1 # increment i
}
combined_results[[iteration]] <- do.call(rbind,results)
}
df <- do.call(rbind,combined_results)
df[df$iteration < 5,]
...y la salida de las 4 primeras iteraciones del bucle externo:
> df[df$iteration < 5,]
iteration index a b
1 1 1 8.682442 8.846653
2 1 2 9.204682 8.501692
3 1 3 8.886819 10.488972
4 1 4 11.264142 8.952981
5 1 5 9.900112 10.918042
6 1 6 9.185120 10.625667
7 1 7 9.620793 10.316724
8 1 8 11.718397 9.256835
9 1 9 10.034793 11.634023
10 2 1 11.634331 9.746453
11 2 2 9.195410 7.665265
12 2 3 11.323344 8.279968
13 2 4 9.617224 11.792142
14 2 5 9.360307 11.166162
15 2 6 7.963320 11.325801
16 2 7 8.022093 8.568503
17 2 8 10.440788 9.026129
18 2 9 10.841408 10.033346
19 3 1 11.618665 10.179793
20 4 1 10.975061 9.503309
21 4 2 10.209288 12.409656
>
De nuevo observamos que la última fila en cada iteración (9, 18, 19, y 21) tienen valores mayores que 10 para ambos a
y b
.
Tenga en cuenta que este enfoque no toma ventaja de vectorizados operaciones en R, lo que significa que en lugar de generar 1,000 números aleatorios con cada llamada a rnorm()
el código que se basa en un while()
genera un único número aleatorio por llamada a rnorm()
. Desde rnorm()
es un uso intensivo de los recursos de la función, el código que minimiza el número de veces rnorm()
ejecuta es deseable.