ガウス分布に従うランダム変数を作成する機能を提供する.NETの標準ライブラリにクラスはありますか?
Random.NextDouble()
)ANY分布のCDFの逆に入れると、THAT分布に従う乱数が得られます。アプリケーションで正確に正規分布された変数が必要ない場合、ロジスティック分布は正規分布に非常に近く、簡単に反転可能なCDFを持っています。
Random
ボックス・ミュラー変換を使用して(以下、いくつかの回答に記載)。
ガウス分布に従うランダム変数を作成する機能を提供する.NETの標準ライブラリにクラスはありますか?
Random.NextDouble()
)ANY分布のCDFの逆に入れると、THAT分布に従う乱数が得られます。アプリケーションで正確に正規分布された変数が必要ない場合、ロジスティック分布は正規分布に非常に近く、簡単に反転可能なCDFを持っています。
Random
ボックス・ミュラー変換を使用して(以下、いくつかの回答に記載)。
回答:
JarrettのBox-Muller変換の使用に関する提案は、迅速でダーティなソリューションに適しています。簡単な実装:
Random rand = new Random(); //reuse this if you are generating many
double u1 = 1.0-rand.NextDouble(); //uniform(0,1] random doubles
double u2 = 1.0-rand.NextDouble();
double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) *
Math.Sin(2.0 * Math.PI * u2); //random normal(0,1)
double randNormal =
mean + stdDev * randStdNormal; //random normal(mean,stdDev^2)
stdDev
変数には何を設定しますか?これは特定の要件に合わせて構成できることを理解していますが、限界(つまり、最大/最小値)はありますか?
この質問はGoogleの.NET Gaussian世代の上位に移動したようですので、私は答えを投稿すると思いました。
Box-Muller変換の実装を含む、.NET Randomクラスの拡張メソッドをいくつか作成しました。これらは拡張機能なので、プロジェクトが含まれている(またはコンパイル済みDLLを参照している)限り、次のことができます。
var r = new Random();
var x = r.NextGaussian();
誰もが恥知らずなプラグを気にしないことを願っています。
結果のサンプルヒストグラム(これを描画するためのデモアプリが含まれています):
Math.NETはこの機能を提供します。方法は次のとおりです。
double mean = 100;
double stdDev = 10;
MathNet.Numerics.Distributions.Normal normalDist = new Normal(mean, stdDev);
double randomGaussianValue= normalDist.Sample();
ここにドキュメントがあります:http : //numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm
Microsoft Connectでそのような機能のリクエストを作成しました。これがあなたが探しているものである場合は、投票してその可視性を高めてください。
この機能はJava SDKに含まれています。その実装はドキュメントの一部として利用でき、 C#または他の.NET言語に簡単に移植できます。
純粋な速度を求めている場合、Zigoratアルゴリズムは一般的に最速のアプローチとして認識されています。
私はこのトピックの専門家ではありませんが、RoboCup 3Dシミュレーションロボットサッカーライブラリにパーティクルフィルターを実装しているときにこの必要性に遭遇し、フレームワークに含まれていないことに驚いていました。
それまでの間Random
、Box Muller極法の効率的な実装を提供するラッパーは次のとおりです。
public sealed class GaussianRandom
{
private bool _hasDeviate;
private double _storedDeviate;
private readonly Random _random;
public GaussianRandom(Random random = null)
{
_random = random ?? new Random();
}
/// <summary>
/// Obtains normally (Gaussian) distributed random numbers, using the Box-Muller
/// transformation. This transformation takes two uniformly distributed deviates
/// within the unit circle, and transforms them into two independently
/// distributed normal deviates.
/// </summary>
/// <param name="mu">The mean of the distribution. Default is zero.</param>
/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>
/// <returns></returns>
public double NextGaussian(double mu = 0, double sigma = 1)
{
if (sigma <= 0)
throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");
if (_hasDeviate)
{
_hasDeviate = false;
return _storedDeviate*sigma + mu;
}
double v1, v2, rSquared;
do
{
// two random values between -1.0 and 1.0
v1 = 2*_random.NextDouble() - 1;
v2 = 2*_random.NextDouble() - 1;
rSquared = v1*v1 + v2*v2;
// ensure within the unit circle
} while (rSquared >= 1 || rSquared == 0);
// calculate polar tranformation for each deviate
var polar = Math.Sqrt(-2*Math.Log(rSquared)/rSquared);
// store first deviate
_storedDeviate = v2*polar;
_hasDeviate = true;
// return second deviate
return v1*polar*sigma + mu;
}
}
Math.NET Iridiumは、「非一様ランダムジェネレーター(通常、ポアソン、二項式など)」の実装も主張しています。
これは、正規分布であるランダム変数を生成するための、もう1つの迅速でダーティなソリューションです。ランダムな点(x、y)を描画し、この点が確率密度関数の曲線の下にあるかどうかを確認します。それ以外の場合は繰り返します。
おまけ:密度関数を置き換えるだけで、他の分布(指数分布やポアソン分布など)の確率変数を生成できます。
static Random _rand = new Random();
public static double Draw()
{
while (true)
{
// Get random values from interval [0,1]
var x = _rand.NextDouble();
var y = _rand.NextDouble();
// Is the point (x,y) under the curve of the density function?
if (y < f(x))
return x;
}
}
// Normal (or gauss) distribution function
public static double f(double x, double μ = 0.5, double σ = 0.5)
{
return 1d / Math.Sqrt(2 * σ * σ * Math.PI) * Math.Exp(-((x - μ) * (x - μ)) / (2 * σ * σ));
}
重要:yの間隔とパラメーターσおよびμを選択して、関数の曲線がその最大/最小点でカットオフしないようにします(例:x = mean)。xとyの間隔は、曲線が収まる境界ボックスと考えることができます。
@yoyoyoyosefの回答をさらに高速化し、ラッパークラスを記述することで拡張したいと思います。発生するオーバーヘッドは2倍の速度ではないかもしれませんが、ほぼ 2倍の速度になるはずです。ただし、スレッドセーフではありません。
public class Gaussian
{
private bool _available;
private double _nextGauss;
private Random _rng;
public Gaussian()
{
_rng = new Random();
}
public double RandomGauss()
{
if (_available)
{
_available = false;
return _nextGauss;
}
double u1 = _rng.NextDouble();
double u2 = _rng.NextDouble();
double temp1 = Math.Sqrt(-2.0*Math.Log(u1));
double temp2 = 2.0*Math.PI*u2;
_nextGauss = temp1 * Math.Sin(temp2);
_available = true;
return temp1*Math.Cos(temp2);
}
public double RandomGauss(double mu, double sigma)
{
return mu + sigma*RandomGauss();
}
public double RandomGauss(double sigma)
{
return sigma*RandomGauss();
}
}
@Noakesと@Hameerの回答から拡張して、「ガウス」クラスも実装しましたが、メモリ空間を簡略化するために、それをランダムクラスの子にして、基本的なNext()、NextDouble()も呼び出せるようにしました、ガウスクラスから同様に、それを処理する追加のRandomオブジェクトを作成する必要はありません。また、_availableおよび_nextgaussグローバルクラスプロパティを削除しました。このクラスはインスタンスベースであるため、必要に応じて表示しなかったため、各スレッドに独自のGaussianオブジェクトを指定すると、スレッドセーフになるはずです。また、ランタイムに割り当てられたすべての変数を関数から移動してクラスプロパティにしました。これにより、メモリマネージャーへの呼び出し回数が減ります。これは、オブジェクトが破棄されるまで、4つのdoubleが理論的に割り当て解除されないためです。
public class Gaussian : Random
{
private double u1;
private double u2;
private double temp1;
private double temp2;
public Gaussian(int seed):base(seed)
{
}
public Gaussian() : base()
{
}
/// <summary>
/// Obtains normally (Gaussian) distrubuted random numbers, using the Box-Muller
/// transformation. This transformation takes two uniformly distributed deviates
/// within the unit circle, and transforms them into two independently distributed normal deviates.
/// </summary>
/// <param name="mu">The mean of the distribution. Default is zero</param>
/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>
/// <returns></returns>
public double RandomGauss(double mu = 0, double sigma = 1)
{
if (sigma <= 0)
throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");
u1 = base.NextDouble();
u2 = base.NextDouble();
temp1 = Math.Sqrt(-2 * Math.Log(u1));
temp2 = 2 * Math.PI * u2;
return mu + sigma*(temp1 * Math.Cos(temp2));
}
}
Drew Noakesの答えを拡張して、Box-Mullerよりも優れたパフォーマンス(約50〜75%高速)が必要な場合は、Colin GreenがC#のZigguratアルゴリズムの実装を共有しています。
http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html
Zigguratは、ルックアップテーブルを使用して、カーブから十分に離れた値を処理します。この値はすぐに受け入れまたは拒否されます。時間の約2.5%で、数値がカーブのどちら側にあるかを判断するために、さらに計算を行う必要があります。
Infer.NETを試すことができます。ただし、まだ商用ライセンスは付与されていません。ここにリンクがあります
これは、Microsoftの研究で開発された.NETの確率的フレームワークです。ベルヌーイ、ベータ、ガンマ、ガウス、ポアソンのディストリビューション用の.NETタイプがあり、おそらく私が省略したものもあります。
それはあなたが望むものを達成するかもしれません。ありがとう。
これは、単純なBox Mullerにインスパイアされた実装です。必要に応じて解像度を上げることができます。これは私にとってはうまく機能しますが、これは範囲が限定された近似であるため、テールが閉じていて有限であることを覚えておいてください。
//
// by Dan
// islandTraderFX
// copyright 2015
// Siesta Key, FL
//
// 0.0 3231 ********************************
// 0.1 1981 *******************
// 0.2 1411 **************
// 0.3 1048 **********
// 0.4 810 ********
// 0.5 573 *****
// 0.6 464 ****
// 0.7 262 **
// 0.8 161 *
// 0.9 59
//Total: 10000
double g()
{
double res = 1000000;
return random.Next(0, (int)(res * random.NextDouble()) + 1) / res;
}
public static class RandomProvider
{
public static int seed = Environment.TickCount;
private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>(() =>
new Random(Interlocked.Increment(ref seed))
);
public static Random GetThreadRandom()
{
return randomWrapper.Value;
}
}
あるとは思いません。そして、フレームワークはすでに十分に肥大化しているので、そのような特殊化された機能がそれをさらに満たしていないことを本当に望みます。
見てみましょうhttp://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspxとhttp://www.vbforums.com/showthread.php?t=488959かかわらず、サードパーティの.NETソリューションの。