私はC++コマンドラインLinuxアプリのいくつかのテストを書いています。べき乗則/ロングテール分布の整数の束を生成したいと思います。つまり、私はいくつかの番号を非常に頻繁に取得しますが、それらのほとんどは比較的まれです。
理想的には、Rand()またはstdlibランダム関数の1つで使用できるいくつかの魔法の方程式があるでしょう。そうでない場合は、C/C++の使いやすいチャンクがあれば素晴らしいでしょう。
ありがとう!
この Wolfram MathWorldのページ は、一様分布(ほとんどの乱数ジェネレーターが提供するもの)からべき乗分布を取得する方法について説明しています。
簡単な答え(上記のリンクからの派生):
x = [(x1^(n+1) - x0^(n+1))*y + x0^(n+1)]^(1/(n+1))
ここで、yは均一変量、nは分布電力、x0とx1は分布の範囲を定義し、xは、べき乗分布の変量です。
必要な分布(確率分布関数(PDF)と呼ばれる)がわかっていて、適切に正規化されている場合は、それを統合して累積分布関数(CDF)を取得し、CDFを反転して(可能な場合)変換を取得できます。均一な_[0,1]
_分布から希望するものまで必要です。
したがって、必要な分布を定義することから始めます。
_P = F(x)
_
([0,1]のxの場合)次に統合して
_C(y) = \int_0^y F(x) dx
_
これを逆にすることができれば、
_y = F^{-1}(C)
_
したがって、Rand()
を呼び出し、結果を最後の行にC
としてプラグインし、yを使用します。
この結果は、サンプリングの基本定理と呼ばれます。これは、正規化の要件と関数を分析的に反転する必要があるため、面倒です。
または、拒否手法を使用することもできます。目的の範囲で均一に数値をスローしてから、別の数値をスローし、最初のスローで指定された場所でPDFと比較します。2番目のスローが超過した場合は拒否します。 PDF。テールが長いPDFのように、確率の低い領域が多いPDFでは非効率になる傾向があります。
中間的なアプローチでは、ブルートフォースによってCDFを反転します。CDFをルックアップテーブルとして保存し、逆ルックアップを実行して結果を取得します。
ここでの本当の悪臭は、単純な_x^-n
_分布が範囲_[0,1]
_で正規化できないため、サンプリング定理を使用できないことです。代わりに(x + 1)^-nを試してください...
べき法則分布を作成するために必要な計算についてコメントすることはできませんが(他の投稿には提案があります)、<random>
のTR1C++標準ライブラリの乱数機能に精通することをお勧めします。これらは、std::Rand
およびstd::srand
よりも多くの機能を提供します。新しいシステムは、ジェネレーター、エンジン、ディストリビューション用のモジュラーAPIを指定し、多数のプリセットを提供します。
含まれている配布プリセットは次のとおりです。
uniform_int
bernoulli_distribution
geometric_distribution
poisson_distribution
binomial_distribution
uniform_real
exponential_distribution
normal_distribution
gamma_distribution
べき法則の分布を定義すると、既存の発電機とエンジンに接続できるはずです。 PeteBeckerによる本C++ Standard Library Extensionsには、<random>
に関するすばらしい章があります。
ここに記事があります 他の分布を作成する方法について(Cauchy、Chi-squared、Student t、Snedecor Fの例を含む)
(当然のことながら)受け入れられた答えを補完するものとして、実際のシミュレーションを実行したかっただけです。 Rでは、コードは(疑似)-疑似コードになるほど単純です。
受け入れられた答えの Wolfram MathWorld式 と他の、おそらくもっと一般的な方程式との小さな違いの1つは、べき乗則指数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)
または対数目盛でプロット:
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")
データの要約は次のとおりです。
> summary(x)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.1000 0.1208 0.1584 0.2590 0.2511 4.9388