Генерация вероятностного распределения
Учитывая массив размера n
Я хочу генерировать случайные вероятности для каждого индекса таким образом, чтобы Sigma(a[0]..a[n-1])=1
Одним из возможных результатов может быть:
0 1 2 3 4
0.15 0.2 0.18 0.22 0.25
Другим совершенно законным результатом может быть:
0 1 2 3 4
0.01 0.01 0.96 0.01 0.01
Как я могу создать это легко и быстро? Ответы на любом языке в порядке, предпочтительнее Java.
6 ответов
Задача, которую вы пытаетесь выполнить, равносильна рисованию случайной точки из N-мерного единичного симплекса.
http://en.wikipedia.org/wiki/Simplex может вам помочь.
Наивное решение может быть следующим:
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;
}
Чтобы нарисовать точку равномерно из N-мерного единичного симплекса, мы должны взять вектор экспоненциально распределенных случайных величин, а затем нормализовать его по сумме этих переменных. Чтобы получить экспоненциально распределенное значение, мы берем отрицательное log
равномерно распределенной стоимости.
Получите n случайных чисел, вычислите их сумму и нормализуйте сумму до 1, разделив каждое число на сумму.
Это относительно поздно, но чтобы показать поправку к простому и прямому ответу @Kobi, приведенному в этой статье, на который указывает @dreeves, который делает выборку равномерной. Метод (если я понимаю это ясно) заключается в
- Генерируйте n-1 различных значений из диапазона [1, 2, ..., M-1].
- Сортировать полученный вектор
- Добавьте 0 и M в качестве первого и последнего элементов результирующего вектора.
- Создайте новый вектор путем вычисления xi - xi-1, где i = 1,2, ... n. То есть новый вектор состоит из различий между последовательными элементами старого вектора.
- Разделите каждый элемент нового вектора на M. У вас равномерное распределение!
Мне любопытно знать, будет ли генерация различных случайных значений и нормализация их до 1 путем деления на их сумму также производить равномерное распределение.
Получите n случайных чисел, вычислите их сумму и нормализуйте сумму до 1, разделив каждое число на сумму.
В продолжение ответа Коби, вот функция Java, которая делает именно это.
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;
}
В тестовом прогоне, getRandDistArray(5)
вернул следующее
[0.1796505603694718, 0.31518724882558813, 0.15226147256596428, 0.30954417535503603, 0.043356542883939767]
Если вы хотите эффективно генерировать значения из нормального распределения, попробуйте преобразование Бокса-Мюллера.
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;
}
Здесь сначала хранятся случайные числа. И флаг сохранит сумму всех сгенерированных чисел, так что на следующем цикле for сгенерированные числа будут разделены на флаг, который в конце массива будет иметь случайные числа в распределении вероятности.