2008-09-16 4 views
85

Как преобразовать равномерное распределение (поскольку большинство генераторов случайных чисел производят, например, между 0.0 и 1.0) в нормальное распределение? Что, если я хочу среднего и стандартного отклонения от моего выбора?Преобразование равномерного распределения в нормальное распределение

+3

У вас есть языковая спецификация, или это просто общий алгоритм? – 2008-09-16 19:08:26

+2

Общий алгоритмный вопрос. Мне все равно, на каком языке. Но я бы предпочел, чтобы ответ не зависел от конкретной функциональности, которую предоставляет только этот язык. – Terhorst 2008-09-16 19:12:23

ответ

44

Ziggurat algorithm довольно эффективен для этого, хотя Box-Muller transform проще реализовать с нуля (и не безумно медленно).

+7

Обычные предупреждения о линейных конгруэнтных генераторах применяются к обоим этим методам, поэтому используйте достойный генератор подрыва. Приветствия. – dmckee 2008-09-16 19:02:04

+3

Например, Mersenee Twister, или у вас есть другие предложения? – 2008-09-18 21:19:28

1

Я бы использовал Box-Muller. Две вещи по этому поводу:

  1. Вы в конечном итоге с двумя значениями на итерации
    Как правило, вы кэшировать одно значение и возвращаете другое. При следующем вызове образца вы возвращаете кешированное значение.
  2. Box-Muller дает Z-счет
    Вы должны затем масштабировать Z-балл стандартным отклонением и добавить среднее значение, чтобы получить полное значение в нормальном распределении.
+0

Как вы масштабируете Z-счет? – Terhorst 2008-09-16 19:18:29

+2

scaled = mean + stdDev * zScore // дает вам нормальный (средний, stdDev^2) – yoyoyoyosef 2008-10-20 14:31:56

1

Стандартный модуль случайных Python библиотека имеет то, что вы хотите:

normalvariate (мю, сигма)
Нормальное распределение. mu - среднее значение, а сигма - стандартное отклонение.

Для самого алгоритма взгляните на функцию в random.py в библиотеке Python.

The manual entry is here

+1

К сожалению, библиотека python использует Kinderman, A.J. и Monahan, J.F., «Компьютерное генерирование случайных величин с использованием отношения однородных отклонений», ACM Trans Math Software, 3, (1977), pp. 257-260. Это использует две равномерные случайные величины для генерации нормального значения, а не для одного, поэтому неясно, как использовать его в качестве отображения, которое требуется OP. – Ian 2011-04-04 17:27:41

-1
function distRandom(){ 
    do{ 
    x=random(DISTRIBUTION_DOMAIN); 
    }while(random(DISTRIBUTION_RANGE)>=distributionFunction(x)); 
    return x; 
} 
+0

Не гарантируется возврат, правда? ;-) – 2008-10-15 02:43:13

+0

он возвращается почти наверняка. – 2010-07-16 13:19:49

+4

Случайные числа слишком важны, чтобы их оставили на волю случая. – 2011-01-03 05:59:15

23

Изменение распределения любой функции к другой предполагает использование обратной функции, которую вы хотите.

Другими словами, если вы стремитесь к определенной вероятностной функции p (x), вы получаете распределение, интегрируя по ней -> d (x) = integ (p (x)) и используя ее обратное: Inv (d (Икс)). Теперь используйте случайную вероятностную функцию (которая имеет равномерное распределение) и передают результат через функцию Inv (d (x)). Вы должны получить случайные значения, отличные от дистрибутива, в соответствии с выбранной вами функцией.

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

Надеюсь, это помогло и спасибо за небольшое замечание об использовании распределения, а не о самой вероятности.

4

Используйте центральную предельную теорему wikipedia entrymathworld entry в ваших интересах.

Сформировать п равномерно распределенных чисел, обобщать их, вычитать п * 0,5 и у вас есть выход приблизительно нормального распределения со средним равным 0 и дисперсией, равной (1/12) * (1/sqrt(N)) (см wikipedia on uniform distributions для этого последнего)

n = 10 дает вам что-то наполовину приличное быстро.Если вы хотите, чтобы что-то более чем наполовину пошло для решения tylers (как указано в wikipedia entry on normal distributions)

20

Вот реализация javascript с использованием полярной формы преобразования Box-Muller.

/* 
* Returns member of set with a given mean and standard deviation 
* mean: mean 
* standard deviation: std_dev 
*/ 
function createMemberInNormalDistribution(mean,std_dev){ 
    return mean + (gaussRandom()*std_dev); 
} 

/* 
* Returns random number in normal distribution centering on 0. 
* ~95% of numbers returned should fall between -2 and 2 
* ie within two standard deviations 
*/ 
function gaussRandom() { 
    var u = 2*Math.random()-1; 
    var v = 2*Math.random()-1; 
    var r = u*u + v*v; 
    /*if outside interval [0,1] start over*/ 
    if(r == 0 || r >= 1) return gaussRandom(); 

    var c = Math.sqrt(-2*Math.log(r)/r); 
    return u*c; 

    /* todo: optimize this algorithm by caching (v*c) 
    * and returning next time gaussRandom() is called. 
    * left out for simplicity */ 
} 
38

Есть много методов:

  • ли не использовать Box Muller. Особенно, если вы рисуете много гауссовских чисел. Box Muller дает результат, который зажат между -6 и 6 (при условии двойной точности. Вещи ухудшаются с поплавками). И это действительно менее эффективно, чем другие доступные методы.
  • Ziggurat - это хорошо, но вам нужен поиск в таблице (и некоторые настройки для конкретной платформы из-за проблем с размером кеша)
  • Соотношение мундиров является моим фаворитом, всего несколько добавлений/умножений и журнал 1/50th из время (например, look there).
  • Инвертирование CDF является эффективным (и упускается из виду, почему?), У вас есть быстрая реализация его доступна, если вы ищете Google. Это обязательно для Квази-случайных чисел.
1

где R 1, R 2 представляют собой случайные равномерные числа:

нормальное распределение, с SD 1: SQRT (-2 * журнал (R1)) * соз (2 * пи * R 2)

Это точно ... не нужно делать все эти медленные петли!

0

Я хочу попробовать это в EXCEL: =norminv(rand();0;1). Это будет производить случайные числа, которые должны нормально распределяться с нулевым средним значением и объединяться с дисперсией. «0» может поставляться с любым значением, так что числа будут иметь желаемое среднее значение, и, изменив «1», вы получите дисперсию, равную квадрату вашего ввода.

Например: =norminv(rand();50;3) уступит нормально распределенных чисел со средним значением = 50 ДИСПЕРСИИ = 9.

0

Q Каким образом можно преобразовать равномерное распределение (поскольку большинство генераторов случайных чисел производят, например, между 0.0 и 1.0), в нормальное распределение?

  1. Для реализации программного обеспечения я знаю пару случайных имен генераторов, которые дают вам псевдо равномерную случайную последовательность в [0,1] (Вихрь Мерсенна, линейный Congruate генератор). Назовем это U (x)

  2. Существует математическая область, которая называется теорией вероятностей. Первое: если вы хотите модель r.v. с интегральным распределением F, то вы можете попробовать только оценить F^-1 (U (x)). В п.теории доказано, что такой р.в. будет иметь интегральное распределение F.

  3. Шаг 2 может быть применен для генерации r.v. ~ F без использования каких-либо методов подсчета, когда F^-1 можно получить аналитически без проблем. (например, exp.распределение)

  4. Чтобы моделировать нормальное распределение, вы можете cacculate y1 * cos (y2), где y1 ~ равномерно в [0,2pi]. и y2 является выпуклым распределением.

В: Что, если я хочу иметь среднее и стандартное отклонение от моего выбора?

Вы можете вычислить сигма * N (0,1) + m.

Можно показать, что такое перемещение и масштабирование приводит к N (м, SIGMA)

1

Это кажется невероятным, что я мог бы что-то добавить к этому после восьми лет, но в случае Java я хотел бы отметить читателей к методу Random.nextGaussian(), который генерирует распределение Гаусса со средним 0.0 и стандартным отклонением 1.0 для вас.

Простое добавление и/или умножение изменят среднее и стандартное отклонение в соответствии с вашими потребностями.

0

Это реализация Matlab с использованием полярной формы Box-Muller трансформации:

Функция randn_box_muller.m:

function [values] = randn_box_muller(n, mean, std_dev) 
    if nargin == 1 
     mean = 0; 
     std_dev = 1; 
    end 

    r = gaussRandomN(n); 
    values = r.*std_dev - mean; 
end 

function [values] = gaussRandomN(n) 
    [u, v, r] = gaussRandomNValid(n); 

    c = sqrt(-2*log(r)./r); 
    values = u.*c; 
end 

function [u, v, r] = gaussRandomNValid(n) 
    r = zeros(n, 1); 
    u = zeros(n, 1); 
    v = zeros(n, 1); 

    filter = r==0 | r>=1; 

    % if outside interval [0,1] start over 
    while n ~= 0 
     u(filter) = 2*rand(n, 1)-1; 
     v(filter) = 2*rand(n, 1)-1; 
     r(filter) = u(filter).*u(filter) + v(filter).*v(filter); 

     filter = r==0 | r>=1; 
     n = size(r(filter),1); 
    end 
end 

И вызова histfit(randn_box_muller(10000000),100); это результат: Box-Muller Matlab Histfit

Очевидно, что это на самом деле неэффективен по сравнению с встроенным Matlab randn.

Смежные вопросы