Fijar semilla en R

Estadística con R Simulación
Aprende qué es y cómo fijar una semilla en R

Cuando generas “números aleatorios” en R, en realidad estás generando números pseudoaleatorios. Estos números se generan con un algoritmo que requiere una semilla para inicializarse. Ser pseudoaleatorio en lugar de puramente aleatorio significa que, si conoces la semilla y el generador, puedes predecir (y reproducir) la secuencia. En este tutorial aprenderás el significado de fijar semilla en R, qué hace y cómo funciona la función set.seed y en consecuencia, cómo crear códigos reproducibles en R.

¿Qué es set seed (fijar semilla) en R?

Fijar una semilla en R significa inicializar un generador de números pseudoaleatorios. La mayoría de los métodos de simulación en Estadística requieren la posibilidad de generar números pseudoaleatorios que imiten las propiedades de generaciones independientes de una distribución uniforme en el intervalo \((0, 1)\).

Para obtener estas secuencias de números pseudoaleatorios, necesitamos un algoritmo recursivo llamado Generador de Números Aleatorios (o RNG, por sus siglas en inglés):

\[x_i = f(x_{i-1}, x_{i-2},x_{i-3}, \dots, x_{i-k}),\]

donde \(k\) es el orden del generador y \((x_0, x_1, x_2, \dots, x_{k-1})\) es la semilla (o el estado inicial del generador).

Ten en cuenta que si conoces el generador y la semilla, los números pseudoaleatorios son predecibles.

Hay varios generadores que se pueden seleccionar con la función RNGkind o con el argumento kind de la función set.seed, que usa por defecto el generador Mersenne-Twister.

¿Por qué fijar semilla en R?

Cuando utilices funciones que muestreen números pseudoaleatorios, cada vez que las ejecutes obtendrás un resultado diferente. Considera, por ejemplo, que quieres obtener una muestra de 5 números de una distribución normal. Para ello, puedes escribir:

rnorm(5)
0.4421843 0.8404235 -1.5879426  0.8557701 -0.1546376

Sin embargo, si ejecutas el código anterior obtendrás un resultado diferente. Esto implica que el código no es reproducible, porque no conoces la semilla que R usó para generar esa secuencia.

Es posible que no quieras que tu código sea reproducible, pero hay varios casos en los que la reproducibilidad es deseable. Establecer una semilla en R se usa para:

  1. Reproducir estudios de simulación.
  2. Ayudar a depurar (debuggear) el código cuando trabajes con números pseudoaleatorios.

¿Cómo usar la función set.seed para fijar semilla?

El propósito de la función set.seed en R es permitirte fijar una semilla inicial y un generador (con el argumento kind). Vale la pena destacar que:

  1. El estado del generador de números aleatorios se almacena en .Random.seed (en el entorno global). Es un vector de enteros cuya longitud depende del generador.
  2. Si la semilla no se especifica, R utiliza el reloj del sistema para establecer una.

Vuelve a ejecutar el ejemplo anterior donde obtuvimos una muestra de cinco números aleatorios de una distribución normal, pero ahora especifica una semilla antes:

# Especifica un entero
set.seed(1) 

rnorm(5) # -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078

Si ejecutas el código anterior, obtendrás el mismo resultado que nosotros. Sin embargo, ten en cuenta que si ejecutas rnorm(5) dos veces seguidas, dará resultados diferentes:

set.seed(1)

rnorm(5) # -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078
rnorm(5) # -0.8204684  0.4874291  0.7383247  0.5757814 -0.3053884

Cabe señalar que el bloque de código anterior devuelve los mismos números pseudoaleatorios que el siguiente código:

set.seed(1)
rnorm(10)
-0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078
-0.8204684  0.4874291  0.7383247  0.5757814 -0.3053884

Esto se debe a que cuando ejecutamos una función que devuelve números aleatorios, la salida depende de los valores de .Random.seed, que cambian después de ejecutar este tipo de funciones. Si almacenas el valor de .Random.seed puedes obtener el estado actual de la semilla.

set.seed(1)
x <- .Random.seed
rnorm(5)

y <- .Random.seed
rnorm(5)

# .Random.seed no es igual en ambos casos
identical(x, y) # FALSE

En consecuencia, en caso de que quisieses generar los mismos números dos veces, debes establecer la misma semilla dos veces:

set.seed(1)
rnorm(5)   # -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078

set.seed(1)
rnorm(5)   # -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078

Como señalamos antes, establecer una semilla en R es útil cuando se trabaja con estudios de simulación. Supón que quieres calcular la mediana de algunos valores que provienen de una distribución uniforme:

# Fijamos semilla
set.seed(1234)  

n_rep <- 10 # Número de repeticiones
n <- 2      # Número de puntos

Mediana <- numeric(n_rep) 

for (i in 1:n_rep) {
    Mediana[i] <- median(runif(n))
}

Mediana

Como utilizamos la función set.seed, si ejecutas el código anterior obtendrás el siguiente resultado:

0.3680014 0.6163271 0.7506130 0.1210231 0.5901674
0.6192831 0.6030835 0.5648057 0.2765220 0.2094744

No obstante, si por alguna razón aparece un error en alguna iteración, no podrás reproducir el error. Para resolver este problema, tienes dos opciones: guardar el valor de .Random.seed o cambiar la semilla en cada iteración:

set.seed(5)

for (i in 1:n_rep) {
  seed <- .Random.seed
  # Si aparece un error podemos depurarlo con: .Random.seed <- seed

  # Código

}
for (i in 1:n_rep) {
    set.seed(i)
    #  Si aparece un error podemos depurarlo con set.seed(i)

    # Código

}

Restablecer semilla

Finalmente, es posible que quieras restablecer o quitar una semilla en R. Para lograrlo, tienes dos opciones:

Por un lado, como R usa el reloj del sistema para establecer una semilla cuando no se especifica, puedes usar la función Sys.time de la siguiente manera para volver al comportamiento predeterminado:

set.seed(Sys.time())

Por otro lado, siguiendo la documentación de la función, puedes pasar NULL a la función, para reinicializar el generador “como si aún no se hubiera establecido una semilla”.

set.seed(NULL)