numeros - random in java
Generando una distribuciĆ³n de probabilidad. (6)
Dada una matriz de tamaño n
, quiero generar probabilidades aleatorias para cada índice tal que Sigma(a[0]..a[n-1])=1
Un posible resultado podría ser:
0 1 2 3 4
0.15 0.2 0.18 0.22 0.25
Otro resultado perfectamente legal puede ser:
0 1 2 3 4
0.01 0.01 0.96 0.01 0.01
¿Cómo puedo generar estos de forma fácil y rápida? Las respuestas en cualquier idioma están bien, se prefiere Java.
Obtenga n números aleatorios, calcule su suma y normalice la suma a 1 dividiendo cada número con la suma.
Ampliando la respuesta de Kobi , aquí hay una función de Java que hace exactamente eso.
public static double[] getRandDistArray(int n) {
double randArray[] = new double[n];
double sum = 0;
// Generate n random numbers
for (int i = 0; i < randArray.length; i++) {
randArray[i] = Math.random();
sum += randArray[i];
}
// Normalize sum to 1
for (int i = 0; i < randArray.length; i++) {
randArray[i] /= sum;
}
return randArray;
}
En una ejecución de prueba, getRandDistArray(5)
devolvió lo siguiente
[0.1796505603694718, 0.31518724882558813, 0.15226147256596428, 0.30954417535503603, 0.043356542883939767]
Esto es relativamente tarde, pero para mostrar la enmienda a la respuesta simple y directa de @ Kobi dada en este paper señalado por @dreeves que hace que el muestreo sea uniforme. El método (si lo entiendo claramente) es
- Genere n-1 valores distintos del rango [1, 2, ..., M-1].
- Ordenar el vector resultante
- Agregue 0 y M como el primer y último elemento del vector resultante.
- Genere un nuevo vector calculando x i - x i-1 donde i = 1,2, ... n. Es decir, el nuevo vector está formado por las diferencias entre elementos consecutivos del vector antiguo.
- Divide cada elemento del nuevo vector por M. ¡Tienes tu distribución uniforme!
Tengo curiosidad por saber si generar valores aleatorios distintos y normalizarlos a 1 dividiéndolos por su suma también producirá una distribución uniforme.
La tarea que está tratando de realizar es equivalente a dibujar un punto aleatorio de la unidad N-dimensional simplex.
http://en.wikipedia.org/wiki/Simplex#Random_sampling podría ayudarlo.
Una solución ingenua podría ser la siguiente:
public static double[] getArray(int n)
{
double a[] = new double[n];
double s = 0.0d;
Random random = new Random();
for (int i = 0; i < n; i++)
{
a [i] = 1.0d - random.nextDouble();
a [i] = -1 * Math.log(a[i]);
s += a[i];
}
for (int i = 0; i < n; i++)
{
a [i] /= s;
}
return a;
}
Para dibujar un punto uniformemente de la unidad simplex de N dimensiones, debemos tomar un vector de variables aleatorias distribuidas exponencialmente , luego normalizarlo por la suma de esas variables. Para obtener un valor distribuido exponencialmente, tomamos un log
negativo de valor distribuido uniformemente.
Obtenga n números aleatorios, calcule su suma y normalice la suma a 1 dividiendo cada número con la suma.
Si desea generar valores a partir de una distribución normal de manera eficiente, pruebe la transformación de Box Muller .
public static double[] array(int n){
double[] a = new double[n];
double flag = 0;
for(int i=0;i<n;i++){
a[i] = Math.random();
flag += a[i];
}
for(int i=0;i<n;i++) a[i] /= flag;
return a;
}
Aquí, al principio, almacena números al azar. Y la bandera mantendrá la suma de todos los números generados de modo que en el siguiente bucle for los números generados se dividirán por la bandera , que al final la matriz tendrá números aleatorios en la distribución de probabilidad.