Случайное число в диапазоне на основе нормального распределения - PullRequest
34 голосов
/ 02 мая 2010

Я хочу генерировать случайные числа с диапазоном (от n до m, например, от 100 до 150), но вместо чисто случайных я хочу, чтобы результаты основывались на нормальном распределении.

Под этим я подразумеваю, что в целом я хочу, чтобы числа «группировались» около 125.

Я нашел этот пакет со случайными числами, который, кажется, содержит много того, что мне нужно: http://codeproject.com/KB/recipes/Random.aspx

Он поддерживает различные генераторы случайных чисел (включая мерсиеновый твистер) и может применять генератор к распределению.

Но я запутался, если я использую генератор нормального распределения, случайные числа будут примерно от -6 до +8 (очевидно, истинный диапазон - от float.min до float.max).

Как сделать масштаб, соответствующий моему требуемому диапазону?

Ответы [ 6 ]

26 голосов
/ 02 мая 2010

Стандартное нормальное распределение имеет среднее значение 0 и стандартное отклонение 1; если вы хотите создать распределение со средним значением m и отклонением s, просто умножьте на s и затем добавьте m. Поскольку нормальное распределение теоретически бесконечно, у вас не может быть жесткой границы вашего диапазона, например (От 100 до 150) без явного отклонения чисел, выходящих за его пределы, но при соответствующем выборе отклонения вы можете быть уверены, что (например) 99% ваших чисел будут в пределах диапазона.

Около 99,7% населения находится в пределах +/- 3 стандартных отклонения, поэтому, если вы выберете для себя значение, равное (25/3), оно должно работать хорошо.

Итак, вы хотите что-то вроде: (normal * 8.333) + 125

14 голосов
/ 02 мая 2010

Ради интереса довольно просто сгенерировать нормально распределенные случайные числа из единого ГСЧ (хотя это должно быть сделано парами):

Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.Pi * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);

x и y теперь содержат два независимых, нормально распределенных случайных числа со средним значением 0 и дисперсией 1. Вы можете масштабировать и переводить их по мере необходимости, чтобы получить нужный диапазон (как объясняет междурядье).


Пояснение:

Этот метод называется преобразованием Бокса-Мюллера . Он использует свойство двумерной единицы Гаусса, состоящее в том, что само значение плотности, p = exp(-r^2/2), равномерно распределено между 0 и 1 (константа нормализации удалена для простоты).

Поскольку вы можете легко сгенерировать такое значение, используя однородный ГСЧ, вы получите круговой контур радиуса r = sqrt(-2 * log(p)). Затем вы можете сгенерировать вторую равномерную случайную величину между 0 и 2*pi, чтобы получить угол θ, который определяет уникальную точку на вашем круговом контуре. Наконец, вы можете сгенерировать два i.i.d. нормальных случайных изменения путем преобразования из полярных координат (r, θ) обратно в декартовы координаты (x, y).

Это свойство - равномерно распределенное p - не распространяется на другие измерения, поэтому вам нужно генерировать ровно две нормальные переменные одновременно.

4 голосов
/ 02 мая 2010

tzaman ответ верен, но при использовании библиотеки, которую вы связали, есть более простой способ, чем выполнять вычисления самостоятельно: объект NormalDistribution имеет свойства записи Mu (что означает среднее значение) и Sigma (стандартное отклонение) , Итак, следуя номерам Цамана, установите Mu на 125 и Sigma на 8,333.

2 голосов
/ 02 мая 2010

Это может быть слишком упрощенно для ваших нужд, но быстрый и дешевый способ получить случайное число с распределением, взвешенным по центру, состоит в простом добавлении 2 (или более) случайных чисел.

Подумайте, когда вы бросаете две 6-гранные кости и добавляете их. Чаще всего сумма равна 7, затем 6 и 8, затем 5 и 9 и т. Д. И только редко 2 или 12.

0 голосов
/ 31 июля 2017

Другой подход к этой проблеме использует бета-распределение (которое имеет жесткий диапазон, в отличие от нормального распределения) и включает выбор соответствующих параметров, так что распределение имеет заданное среднее значение и стандартное отклонение ( квадратный корень дисперсии). См этот вопрос .

0 голосов
/ 09 октября 2015

Вот другой алгоритм, который не должен вычислять Sin / Cos, и при этом ему не нужно знать Pi. Не спрашивайте меня о теоретических основах. Я нашел это где-то один раз, и это то, что я использую с тех пор. Я подозреваю, что это некая нормализация того же преобразования Бокса-Мюллера, о котором упоминает @Will Vousden. Он также дает результаты в парах.

Примером является VBscript; достаточно легко конвертировать на любой другой язык.

Sub calcRandomGauss (byref y1, byref y2)
    Dim x1, x2, w
    Do
        x1 = 2.0 * Rnd() - 1.0
        x2 = 2.0 * Rnd() - 1.0
        w = x1 * x1 + x2 * x2
    Loop While w >= 1.0 Or w = 0  'edited this line, thanks Richard

    w = Sqr((-2.0 * Log(w)) / w )
    y1 = x1 * w
    y2 = x2 * w
End Sub
...