Números aleatorios que suman 100: Matlab

Resuelto Tetra asked hace 13 años • 4 respuestas

[Estoy dividiendo un número de población en diferentes matrices y quiero probar mi código usando números aleatorios por ahora.]

Pregunta rápida chicos y gracias por su ayuda de antemano.

Si uso;

 100*rand(9,1)

¿Cuál es la mejor manera de hacer que estos 9 números sumen 100?

Me gustaría 9 números aleatorios entre 0 y 100 que sumen 100.

¿Hay algún comando incorporado que haga esto porque parece que no puedo encontrarlo?

Tetra avatar Nov 09 '11 18:11 Tetra
Aceptado

Veo el error muy a menudo, la sugerencia de que para generar números aleatorios con una suma dada, uno simplemente usa un conjunto aleatorio uniforme y simplemente los escala. Pero, ¿el resultado es verdaderamente uniformemente aleatorio si se hace de esa manera?

Pruebe esta sencilla prueba en dos dimensiones. Genere una muestra aleatoria enorme y luego escale para que sumen 1. Usaré bsxfun para hacer el escalado.

xy = rand(10000000,2);
xy = bsxfun(@times,xy,1./sum(xy,2));
hist(xy(:,1),100)

Si fueran verdaderamente uniformemente aleatorios, entonces la coordenada x sería uniforme, al igual que la coordenada y. Cualquier valor tendría la misma probabilidad de ocurrir. En efecto, para que dos puntos sumen 1 deben estar a lo largo de la línea que conecta los dos puntos (0,1), (1,0) en el plano (x,y). Para que los puntos sean uniformes, cualquier punto a lo largo de esa línea debe ser igualmente probable.

histograma xy

Claramente, la uniformidad falla cuando uso la solución de escala. Cualquier punto en esa línea NO es igualmente probable. Podemos ver lo mismo sucediendo en 3 dimensiones. Observe que en la figura tridimensional aquí, los puntos en el centro de la región triangular están más densamente empaquetados. Esto es un reflejo de la falta de uniformidad.

xyz = rand(10000,3);
xyz = bsxfun(@times,xyz,1./sum(xyz,2));
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on

diagrama xyz

Una vez más, la solución de escala simple falla. Simplemente NO produce resultados verdaderamente uniformes en el dominio de interés.

¿Podemos hacerlo mejor? Bueno, sí. Una solución simple en 2-d es generar un único número aleatorio que designe la distancia a lo largo de la línea que conecta los puntos (0,1) y 1,0).

t = rand(10000000,1);
xy = t*[0 1] + (1-t)*[1 0];
hist(xy(:,1),100)

Uniforme x+y = 1

Se puede demostrar que CUALQUIER punto a lo largo de la recta definida por la ecuación x+y = 1, en el cuadrado unitario, ahora tiene la misma probabilidad de haber sido elegido. Esto se refleja en el bonito y plano histograma.

¿El truco de clasificación sugerido por David Schwartz funciona en n dimensiones? Claramente lo hace en 2 dimensiones, y la siguiente figura sugiere que lo hace en 3 dimensiones. Sin pensar profundamente al respecto, creo que funcionará para este caso básico en cuestión, en n dimensiones.

n = 10000;
uv = [zeros(n,1),sort(rand(n,2),2),ones(n,1)];
xyz = diff(uv,[],2);

plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
box on
grid on
view(70,35)

ordenar truco

También se puede descargar la función randfixedsum desde el intercambio de archivos, contribución de Roger Stafford. Esta es una solución más general para generar conjuntos aleatorios verdaderamente uniformes en el hipercubo unitario, con cualquier suma fija dada. Por lo tanto, para generar conjuntos aleatorios de puntos que se encuentran en el cubo unitario de 3, sujeto a la restricción, suman 1,25...

xyz = randfixedsum(3,10000,1.25,0,1)';
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on

suma fijada

 avatar Nov 09 '2011 17:11

Una forma sencilla es elegir 8 números aleatorios entre 0 y 100. Suma 0 y 100 a la lista para obtener 10 números. Ordenarlos. Luego genere la diferencia entre cada par sucesivo de números. Por ejemplo, aquí hay 8 números aleatorios entre 0 y 100:

96, 38, 95, 5, 13, 57, 13, 20

Entonces suma 0 y 100 y ordena.

0, 5, 13, 13, 20, 38, 57, 95, 96, 100

Ahora resta:

5-0 = 5
13-5 = 8
13-13 = 0
20-13 = 7
38-20 = 18
57-38 = 19
95-57 = 38
96-95 = 1
100-96 = 4

Y ahí lo tienes, nueve números que suman 100: 0, 1, 4, 5, 7, 8, 18, 19, 38. Que obtuviera un cero y un uno fue simplemente una extraña suerte.

David Schwartz avatar Nov 09 '2011 12:11 David Schwartz

No es demasiado tarde para dar la respuesta correcta.

Hablemos de muestrear X1...XN en el rango [0...1] de modo que Sum(X1, ..., XN) sea igual a 1. Luego podrías reescalarlo a 100.

Esto se llama distribución Dirichlet y a continuación se muestra el código para tomar una muestra. El caso más simple es cuando todos los parámetros son iguales a 1, entonces todas las distribuciones marginales para X1, ..., XN serían U(0,1). En el caso general, con parámetros diferentes de 1, las distribuciones marginales pueden tener picos.

----------------- tomado de aquí ---------------------

El Dirichlet es un vector de variables aleatorias gamma de escala unitaria, normalizadas por su suma. Entonces, sin verificación de errores, esto le dará lo siguiente:

a = [1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0]; // 9 numbers to sample
n = 10000;
r = drchrnd(a,n)

function r = drchrnd(a,n)
  p = length(a);
  r = gamrnd(repmat(a,n,1),1,n,p);
  r = r ./ repmat(sum(r,2),1,p);
Severin Pappadeux avatar Jul 26 '2017 21:07 Severin Pappadeux