Ir al contenido
σestadistica.ar

Tabla

Números aleatorios con semilla

Lo que hacía valiosa a la tabla impresa no era el azar: era que cualquiera podía comprobar que la muestra había salido de ahí. Esta la reemplaza sin perder eso.

Para lo que la tabla se usa de verdad: sacar la muestra y dejar constancia.

Las 40 unidades, ordenadas

79 164 173 201 221 235 287 290 294 312 314 317 349 351 357 389 393 402 493 524 554 612 648 733 745 812 816 856 873 894 906 915 960 989 993 1059 1125 1132 1134 1157

Cada unidad tuvo probabilidad 40/1.200 = 3,33 % de entrar.

En el orden en que salieron

733 993 294 1132 164 389 287 812 314 856 915 79 349 1134 906 402 290 989 357 524 312 816 1059 554 317 612 173 221 873 1157 201 493 745 960 894 1125 235 351 648 393

Esta es la secuencia que devuelve R, y es la que hay que guardar para que la selección se pueda auditar. Si además hace falta reemplazar bajas, los que siguen en este orden son los suplentes.

Lo mismo, en R

set.seed(2026)
muestra <- sample(1200, 40)
sort(muestra)

Devuelve exactamente lo mismo que esta página: es el mismo generador, reproducido bit por bit.

En Python

import numpy as np
# El generador de numpy no es el de R: los números no coinciden.
azar = np.random.default_rng(2026)
np.sort(azar.choice(np.arange(1, 1201), size=40, replace=False))

Acá los números no coinciden: NumPy usa otro generador. Sirve para sacar una muestra, no para reproducir esta.

Por qué una tabla y no un dado

Las tablas de números aleatorios de los libros de muestreo —la de Kendall y Babington Smith, la de la RAND con su millón de dígitos— existían por una razón que no era la comodidad. Un dado, una moneda o una bolsa con papelitos producen azar perfectamente válido y perfectamente inauditable: terminado el sorteo no queda rastro de cómo se hizo, y quien quiera discutir la selección no tiene contra qué compararla.

La tabla resolvía eso. Si el informe decía «entré por la fila 7, columna 3», el que auditaba conseguía el libro y verificaba. La selección quedaba reproducible, que en muestreo no es una comodidad sino la condición para que alguien pueda revisarla.

Lo que cambia con la computadora

Math.random() del navegador no se puede sembrar, cambia de una versión a otra y no deja rastro. Una muestra sacada con él está en la misma posición que la bolsa con papelitos: no se puede volver a sacar, ni auditar, ni defender ante un tribunal que pregunte cómo se eligió.

Por eso acá el azar no es el del navegador. Es el Mersenne-Twister de R, con su sembrado de set.seed() y el muestreo por rechazo que R usa desde la versión 3.6, reproducido bit por bit. La consecuencia práctica es que el recuadro con el código de R de abajo devuelve exactamente los mismos números en cualquier R del mundo. La semilla cumple el papel del «entré por la fila 7»: es el dato que hace auditable a la selección.

set.seed(2026)
muestra <- sample(1200, 40)
sort(muestra)

Con Python es distinto y la página lo dice: NumPy usa otro generador, así que el código que aparece al costado saca una muestra válida pero no reproduce esta. Para que una selección sea auditable, quien la revisa tiene que usar el mismo motor.

Los tres modos

La grilla de dígitos es la tabla clásica, en bloques de cinco. Los bloques no tienen ningún significado estadístico: están para no perder el renglón al leer con el dedo. Sirve para enseñar el procedimiento —se elige un punto de entrada, se leen tantos dígitos como cifras tenga el N y se descarta lo que se pase— y para trabajar sin computadora.

Elegir n de N es para lo que la tabla se usa de verdad. Devuelve dos listas y las dos importan: la ordenada, que es la que se lleva al trabajo de campo, y la del orden de salida, que es la que hay que guardar. Reordenar la secuencia que produjo el generador vuelve incomprobable la selección; y si después hay que reemplazar bajas, los que siguen en ese orden son los suplentes, elegidos con el mismo sorteo y no con otro.

Repartir en grupos no es muestreo sino aleatorización, y la diferencia importa: acá no se elige a quién estudiar sino quién recibe cada tratamiento. El reparto se hace permutando las unidades y cortando la permutación en tramos. Sortear el grupo de cada unidad por separado sería más simple y daría grupos de tamaño desigual por puro azar —con 60 unidades en 3 grupos, salir 25-20-15 es perfectamente posible—, y esa desigualdad se paga en potencia.

El sesgo que R corrigió en 2019

Hasta la versión 3.6, R convertía un número real en un entero entre 1 y N multiplicando y truncando. Eso parece inofensivo y no lo es: como el real tiene 32 bits de resolución, con N grande algunos enteros salen sistemáticamente más seguido que otros. El sesgo es chico pero medible, y fue suficiente para que R cambiara el método por muestreo por rechazo —sortear bits, descartar lo que se pasa y volver a tirar—, que es el que está reproducido acá.

La consecuencia es que una selección hecha con R 3.5 y otra con R 3.6, con la misma semilla, no coinciden. Si hay que reproducir una selección vieja, no alcanza con la semilla: hace falta también la versión.

Cómo está verificado

Contra R de verdad. Un script genera la referencia con R 4.5.2 —dígitos con reposición, selecciones sin reposición, permutaciones completas y repartos en grupos— y el verificador compara contra ese archivo siempre, para poder correr en integración continua sin instalar R, y además vuelve a generarlo en vivo cuando encuentra R en la máquina y exige que los dos coincidan.

Los casos no son al azar: buscan los bordes donde una copia del generador se desvía. Poblaciones que son potencias de dos exactas o se pasan por uno —64, 65, 65.536, 65.537—, donde cambia la cantidad de bits que pide el rechazo; 65.536 en particular, donde el generador de R hace dos tandas de 16 bits y no una; semillas negativas, cero y el máximo entero; y el caso n = N, que es la permutación completa. Se comprueban también las propiedades que no dependen de R: que los dígitos salgan uniformes, que ninguna unidad se repita, que los grupos sean una partición exacta y que dos semillas distintas den resultados distintos.