Генератор случайных чисел, который производит распределение по закону мощности?

Я пишу некоторые тесты для приложения командной строки c++ Linux. Я хотел бы создать кучу целых чисел с распределением power-law/long-tail. Это означает, что я получаю некоторые цифры очень часто, но большинство из них относительно редко.

В идеале было бы просто несколько магических уравнений, которые я мог бы использовать с rand() или одной из случайных функций stdlib. Если нет, простой в использовании кусок C / C++ было бы здорово.

спасибо!

4 ответов


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

короткий ответ (вывод по приведенной выше ссылке):

x = [(x1^(n+1) - x0^(n+1))*y + x0^(n+1)]^(1/(n+1))

здесь y единый вариативной, n распределение власти, x0 и x1 определите диапазон распределения и x ваша власть-закон распространяется вариативной.


если вы знаете распределение, которое хотите (называемое функцией распределения вероятности (PDF)), и оно правильно нормализовано, вы можете интегрировать его, чтобы получить кумулятивную функцию распределения (CDF), а затем инвертировать CDF (если это возможно), чтобы получить преобразование, которое вам нужно от uniform [0,1] рассылки по вашему желанию.

Итак, вы начинаете с определения распределения, которое хотите.

P = F(x)

(для x в [0,1]) затем интегрировано, чтобы дать

C(y) = \int_0^y F(x) dx

если этот можно перевернуть вы получите

y = F^{-1}(C)

так называем rand() и подключите результат как C в последней строке и используйте y.

этот результат называется фундаментальной теоремой выборки. Это хлопот из-за требования нормализации и необходимости аналитически инвертировать функцию.

попеременно вы можете использовать метод отклонения: бросьте число равномерно в желаемом диапазоне, затем бросьте другое число и сравните с PDF в месте indeicated на свой первый бросок. Отклонить, если второй бросок превышает PDF. Как правило, неэффективно для PDF-файлов с большим количеством областей с низкой вероятностью, таких как с длинными хвостами...

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


настоящий вонючка здесь это просто x^-n дистрибутивы не являются нормируемыми в диапазоне [0,1], поэтому вы не можете использовать теорема отсчетов. Попробуйте (x+1)^-n вместо этого...


Я не могу прокомментировать математику, необходимую для создания распределения закона мощности (у других сообщений есть предложения), но я бы предложил вам ознакомиться с объектами случайных чисел стандартной библиотеки TR1 C++ в <random>. Они обеспечивают больше функциональности, чем std::rand и std::srand. Новая система определяет модульный API для генераторов, двигателей и распределений и поставляет кучу пресетов.

включенные пресеты распределения являются:

  • uniform_int
  • bernoulli_distribution
  • geometric_distribution
  • poisson_distribution
  • binomial_distribution
  • uniform_real
  • exponential_distribution
  • normal_distribution
  • gamma_distribution

когда вы определяете ваше распределение закона силы, вы должны мочь заткнуть его внутри с существующими генераторами и двигателями. Книга Расширения Стандартной Библиотеки C++ Пит Бекер многие глава о <random>.

вот статья о том, как создавать другие дистрибутивы (с примерами для Коши, Хи-квадрат, Student t и Snedecor F)


Я просто хотел провести реальное моделирование в качестве дополнения к (по праву) принято отвечать. Хотя в R код настолько прост, что является (псевдо)-псевдо-кодом.

одна крошечная разница между формула вольфрама MathWorld в принятом ответе и других, возможно, более распространенных, уравнениях есть тот факт, что показатель степенного закона n (который обычно обозначается как "Альфа") не несет явный отрицательный знак. Так выбрали Альфа-значение должно быть отрицательным, и обычно между 2 и 3.

x0 и x1 подставка для нижнего и верхнего пределов распространения.

так вот:

x1 = 5           # Maximum value
x0 = 0.1         # It can't be zero; otherwise X^0^(neg) is 1/0.
alpha = -2.5     # It has to be negative.
y = runif(1e5)   # Number of samples
x = ((x1^(alpha+1) - x0^(alpha+1))*y + x0^(alpha+1))^(1/(alpha+1))
hist(x, prob = T, breaks=40, ylim=c(0,10), xlim=c(0,1.2), border=F, 
col="yellowgreen", main="Power law density")
lines(density(x), col="chocolate", lwd=1)
lines(density(x, adjust=2), lty="dotted", col="darkblue", lwd=2)

enter image description here

или нанесены в логарифмическом масштабе:

h = hist(x, prob=T, breaks=40, plot=F)
     plot(h$count, log="xy", type='l', lwd=1, lend=2, 
     xlab="", ylab="", main="Density in logarithmic scale")

enter image description here

вот краткое изложение данных:

> summary(x)
   Min.   1st Qu.  Median    Mean   3rd Qu.    Max. 
  0.1000  0.1208  0.1584    0.2590  0.2511   4.9388