ランダムガウス変数


118

ガウス分布に従うランダム変数を作成する機能を提供する.NETの標準ライブラリにクラスはありますか?


http://mathworld.wolfram.com/Box-MullerTransformation.html 2つのランダム変数を使用すると、ガウス分布に沿ってランダムな値を生成できます。それはまったく難しいことではありません。
Jarrett Meyer、

1
(複雑なCDFのため)正規分布にはすぐには役に立たないが、他の多くの分布には役立つ数学的な結果を追加したいと思います。[0,1]の一様に分布した乱数を(を使用してRandom.NextDouble())ANY分布のCDFの逆に入れると、THAT分布に従う乱数が得られます。アプリケーションで正確に正規分布された変数が必要ない場合、ロジスティック分布は正規分布に非常に近く、簡単に反転可能なCDFを持っています。
Ozzah

1
MedallionRandom NuGetパッケージはから正規分布の値を取得するための拡張メソッドが含まRandomボックス・ミュラー変換を使用して(以下、いくつかの回答に記載)。
ChaseMedallion 2016年

回答:


181

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)

3
私はそれをテストし、MathNetのMersenne Twister RNGおよびNormalDistributionと比較しました。バージョンは2倍以上速く、最終結果は基本的に同じです(「ベル」の目視検査)。
ヨハンゲレル

4
@Johann、純粋な速度を求めている場合、Zigoratアルゴリズムは一般的に最速のアプローチとして認識されています。さらに、上記のアプローチは、1つの呼び出しから次の呼び出しに値を運ぶことにより、より高速にすることができます。
Drew Noakes、2011年

こんにちは、stdDev変数には何を設定しますか?これは特定の要件に合わせて構成できることを理解していますが、限界(つまり、最大/最小値)はありますか?
hofnarwillie 2013

@hofnarwillie stdDevは正規分布のスケールパラメーターであり、任意の正の数にすることができます。それが大きいほど、生成される数値はより分散します。標準正規分布の場合、パラメーター平均= 0および標準偏差= 1を使用します。
yoyoyoyosef 2013

1
@ジャック私はそうは思いません。-2 * Math.Log(u1)のみがsqrt内にあり、u1 <= 1であるため、ログは常に負またはゼロになります
yoyoyoyosef

62

この質問はGoogleの.NET Gaussian世代の上位に移動したようですので、私は答えを投稿すると思いました。

Box-Muller変換の実装を含む、.NET Randomクラスの拡張メソッドをいくつか作成しました。これらは拡張機能なので、プロジェクトが含まれている(またはコンパイル済みDLLを参照している)限り、次のことができます。

var r = new Random();
var x = r.NextGaussian();

誰もが恥知らずなプラグを気にしないことを願っています。

結果のサンプルヒストグラム(これを描画するためのデモアプリが含まれています):

ここに画像の説明を入力してください


あなたの拡張クラスには、私が探していたものがいくつかあります!ありがとう!
トーマス

1
NextGaussianメソッドに小さなバグがあります。NextDouble()0.0以上1.0未満のランダムな浮動小数点数を返します。したがって、u1 = 1.0-NextDouble()...が必要です。他のlog(0)が爆発します
Mitch Wheat

21

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


正解です。この関数は、MathNet.Numericsパッケージの NuGetで使用できます。自分で転がる必要がないのはいつでも素晴らしいことです。
jpmc26

8

Microsoft Connectでそのような機能のリクエストを作成しました。これがあなたが探しているものである場合は、投票してその可視性を高めてください。

https://connect.microsoft.com/VisualStudio/feedback/details/634346/guassian-normal-distribution-random-numbers

この機能は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;
    }
}

私はそれからいくつかの-ve値を得ました。誰かが何が問題かを確認できますか?
mk7

@ mk7、ゼロを中心とするガウス確率関数は、正の値を与えるのと同じくらい、負の値を与える可能性が高いです。
Drew Noakes 2016年

あなたが正しい!ガウスPDFを使用して一般的な母集団の重みのリストを取得したいので、muをたとえば75 [kg]に設定し、sigmaを10に設定します。生成のためにGaussianRandomの新しいインスタンスを設定する必要がありますかすべてのランダムな重み?
mk7 2016年

1つのインスタンスからサンプルを描画し続けることができます。
Drew Noakes 2016年


4

これは、正規分布であるランダム変数を生成するための、もう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)。xyの間隔は、曲線が収まる境界ボックスと考えることができます。


4
Tangenialが、これは実際に私はあなたの代わりに_sigmaまたは_phiのようなダム何かの変数のためのUnicodeの記号を使用することができます実現したのは初めてです...
Slothario

@Slotharioどこでも開発者に「何かおかしい」を使用してくれたことに感謝します:|
user2864740

2

@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();
    }
}

2

@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));
    }
}

ローカル変数も友達です。
user2864740

1

Drew Noakesの答えを拡張して、Box-Mullerよりも優れたパフォーマンス(約50〜75%高速)が必要な場合は、Colin GreenがC#のZigguratアルゴリズムの実装を共有しています。

http://heliosphan.org/zigguratalgorithm/zigguratalgorithm.html

Zigguratは、ルックアップテーブルを使用して、カーブから十分に離れた値を処理します。この値はすぐに受け入れまたは拒否されます。時間の約2.5%で、数値がカーブのどちら側にあるかを判断するために、さらに計算を行う必要があります。


0

Infer.NETを試すことができます。ただし、まだ商用ライセンスは付与されていません。ここにリンクがあります

これは、Microsoftの研究で開発された.NETの確率的フレームワークです。ベルヌーイ、ベータ、ガンマ、ガウス、ポアソンのディストリビューション用の.NETタイプがあり、おそらく私が省略したものもあります。

それはあなたが望むものを達成するかもしれません。ありがとう。


0

これは、単純な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;
   }
} 

これは、単純なBox Mullerにインスパイアされた実装です。必要に応じて解像度を上げることができます。これは非常に高速でシンプルであり、仕事を行うために近似ガウス型の確率密度関数を必要とする私のニューラルネットアプリで機能します。誰かが時間とCPUサイクルを節約するのに役立つことを願っています。これは私にとってはうまく機能しますが、これは範囲が限定された近似であるため、テールが閉じていて有限であることを覚えておいてください。
ダニエルハワード

1
ダニエルさん、コメントの説明を回答自体に組み込む編集を提案しました。また、回答の実際のコードをコメント化していた「//」も削除します。必要に応じて、または拒否された場合は、自分で編集できます:)
mbrig

-1

あるとは思いません。そして、フレームワークはすでに十分に肥大化しているので、そのような特殊化された機能がそれをさらに満たしていないことを本当に望みます。

見てみましょうhttp://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspxhttp://www.vbforums.com/showthread.php?t=488959かかわらず、サードパーティの.NETソリューションの。


7
ガウス分布はいつ「特化」されているのですか?たとえば、AJAXやDataTablesよりもはるかに一般的です。
TraumaPony 2008年

@TraumaPony:AJAXを定期的に使用するよりも多くの開発者がガウス分布を使用することを真剣に提案しようとしていますか?
David Arno、

3
おそらく; 私が言っていることは、それがはるかに専門化されているということです。1つのuse-webアプリしかありません。ガウス分布には、信じられないほど多くの無関係な用途があります。
TraumaPony 2008年

@DavidArno、機能性を減らすことでフレームワークを改善することを真剣に提案していますか
Jodrell 2012年

1
@Jodrellは、具体的な例を挙げれば、MVCをメインの.NETフレームワークの一部ではなく、別個のフレームワークにするという決定は良いものだったと思います。
David Arno
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.