Javascript: генерировать случайные числа с фиксированным средним и стандартным отклонением

Мой вопрос:

Как создать список случайных чисел с заданным средним и стандартным отклонением (sd) в Javascript?

Пример:

Я хочу создать список из 5 случайных чисел в диапазоне от 1 до 10. Результирующее среднее значение должно быть 5, а стандартное отклонение должно быть 2.

Что я сделал до сих пор:

Моя идея была (http://jsfiddle.net/QASDG/3/):

  • Сделайте функцию (с именем "createData" ), которая создает 5 случайных чисел от 1 до 10 и вставляет их в "массив"
  • Эта функция также должна вычислять среднее (и sd) этих 5 чисел.
  • С "do-while" -loop: выполните вышеуказанную функцию, пока "среднее значение станет равным 5" (и "sd станет 2" ). Но когда я звоню в Loop, браузер, конечно, падает, потому что есть много случаев, когда среднее значение равно = 5 (и sd!= 2).

Примечание. Я еще не добавил SD, так как код не очень элегантный.

Я нашел еще один script с этого сайта, который заявил: "Цель этого кода - создать коллекцию, заполненную 5 нормально распределенными случайными числами со средним значением 1.0 и стандартным отклонением 0,5". http://rosettacode.org/wiki/Random_numbers#JavaScript. Я попытался настроить его в соответствии с моими потребностями, добавив "Math.floor" и изменив условие в "for" -loop (i < 5).

function randomNormal() {
    return Math.floor(Math.cos(2 * Math.PI * Math.random()) * Math.sqrt(-2 * Math.log(Math.random())))
}

var a = []
for (var i=0; i < 5; i++){
    a[i] = randomNormal() / 2 + 1
}

Как я хочу изменить свой код:

Я не совсем уверен, понял ли я математическую часть этого кода. Согласно веб-странице, это создаст нормальное распределение (что здорово, но не обязательно). Так что мне нужно дополнительно:

  • Где я могу изменить заданное значение и sd (например, mean = 5, sd = 2), чтобы создать случайные числа (которые выполняют эти свойства).
  • Как реализовать диапазон от 1 до 10? (Возможно, я мог бы использовать что-то вроде: Math.floor(Math.random() * 10) +1)

Спасибо большое!

Ответ 1

Как создать список случайных чисел с заданным средним и стандартным отклонением (sd) в JavaScript?

Это, по-видимому, вопрос о случайном создании списка чисел с точно указанным mean и точно указанным стандартное отклонение (а не вопрос о том, как рисовать случайные числа из определенного распределения вероятности с заданным значением и sd).

Простое решение состоит в том, чтобы нарисовать список случайных чисел, затем сдвинуть и масштабировать этот список, чтобы иметь желаемое среднее значение и sd, как описанное в этом ответе, из stats.stackexchange.

Скажем, мы генерируем следующие 5 случайных чисел между 1 и 10:

4.527991433628388
6.3254986488276055
5.123502737960912
7.3331068522336125
9.069573681037484

Этот список имеет среднее значение 6.475934670737601 и sd 1.8102412442104023.

Затем мы преобразуем каждое число в список следующим образом:

newNum = oldSD * (oldNum - oldMean) / oldSD + newMean

Установив новое среднее значение 5 и новый sd на 2, мы получим следующий преобразованный список:

2.847863379160965
4.83379450402964
3.505799227476338
5.947025358346529
7.865517530986525

Вычисление среднего и sd этого списка подтверждает, что они действительно 5 и 2.

Ниже приведен код, демонстрирующий этот подход в JavaScript:

// create a list of 5 random numbers between 1 and 10
var list = randomList(5, 1, 10);

// transform the list to have an exact mean of 5 and sd of 2
var newList = forceDescriptives(list, 5, 2);

// display the transformed list and descriptive statistics (mean and sd)
console.log('Transformed random list', newList, descriptives(newList));

// display the original list and descriptive statistics (mean and sd)
console.log('Original random list', list, descriptives(list));


/* demo functions */

function randomList(n, a, b) {
  // create a list of n numbers between a and b
  var list = [],
    i;
  for (i = 0; i < n; i++) {
    list[i] = Math.random() * (b - a) + a;
  }
  return list;
}

function descriptives(list) {
  // compute mean, sd and the interval range: [min, max]
  var mean,
    sd,
    i,
    len = list.length,
    sum,
    a = Infinity,
    b = -a;
  for (sum = i = 0; i < len; i++) {
    sum += list[i];
    a = Math.min(a, list[i]);
    b = Math.max(b, list[i]);
  }
  mean = sum / len;
  for (sum = i = 0; i < len; i++) {
    sum += (list[i] - mean) * (list[i] - mean);
  }
  sd = Math.sqrt(sum / (len - 1));
  return {
    mean: mean,
    sd: sd,
    range: [a, b]
  };
}

function forceDescriptives(list, mean, sd) {
  // transfom a list to have an exact mean and sd
  var oldDescriptives = descriptives(list),
    oldMean = oldDescriptives.mean,
    oldSD = oldDescriptives.sd,
    newList = [],
    len = list.length,
    i;
  for (i = 0; i < len; i++) {
    newList[i] = sd * (list[i] - oldMean) / oldSD + mean;
  }
  return newList;
}