Rastgele Gauss Değişkenleri


118

Standart .NET kitaplığında, bana Gauss dağılımını takip eden rastgele değişkenler oluşturma işlevselliği sağlayan bir sınıf var mı?


http://mathworld.wolfram.com/Box-MullerTransformation.html İki rastgele değişken kullanarak, bir Gauss dağılımı boyunca rastgele değerler üretebilirsiniz. Hiç de zor bir iş değil.
Jarrett Meyer

1
Normal dağılımlar için (karmaşık CDF nedeniyle) hemen kullanışlı olmayan, ancak diğer birçok dağıtım için yararlı olan matematiksel bir sonuç eklemek istiyorum. [0,1] 'e (ile Random.NextDouble()) tekdüze dağıtılmış rasgele sayıları HERHANGİ bir dağılımın CDF'sinin tersine koyarsanız , BU dağılımı izleyen rasgele sayılar alırsınız. Uygulamanız tam olarak normal dağıtılmış değişkenlere ihtiyaç duymuyorsa, Lojistik Dağıtım normale çok yakın bir yaklaşımdır ve kolayca tersine çevrilebilir bir CDF'ye sahiptir.
Ozzah

1
MedallionRandom Nuget paketi bir normal olarak dağıtılmış değerleri almak için bir uzatma yöntemi içeren RandomBox-Muller dönüşümü kullanılarak (aşağıda birkaç cevaplarda sözü).
ChaseMedallion

Yanıtlar:


181

Jarrett'ın Box-Muller dönüşümü kullanma önerisi, hızlı ve kirli bir çözüm için iyidir. Basit bir uygulama:

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
Test ettim ve MathNet'in Mersenne Twister RNG ve NormalDistribution ile karşılaştırdım. Sürümünüz iki katından daha hızlıdır ve sonuç temelde aynıdır ("çanların" görsel denetimi).
Johann Gerell

4
@Johann, saf hız arıyorsanız, Zigorat Algoritması genellikle en hızlı yaklaşım olarak kabul edilir. Ayrıca yukarıdaki yaklaşım, bir çağrıdan diğerine bir değer taşınarak daha hızlı yapılabilir.
Drew Noakes

Merhaba, stdDevdeğişken neye ayarlanmalıdır? Bunun belirli gereksinimlere göre yapılandırılabileceğini anlıyorum, ancak herhangi bir sınır var mı (yani maks / min değerler)?
hofnarwillie

@hofnarwillie stdDev, herhangi bir pozitif sayı olabilen normal dağılımın ölçek parametresidir. Ne kadar büyük olursa, üretilen sayılar o kadar dağınık olacaktır. Standart bir normal dağılım için ortalama = 0 ve stdDev = 1 parametrelerini kullanın.
yoyoyoyosef

1
@Jack Sanmıyorum. Yalnızca -2 * Math.Log (u1) sqrt'nin içindedir ve u1 <= 1
yoyoyoyosef

63

Bu soru, .NET için Google'ın Gaussian neslinin üstüne çıkmış gibi görünüyor, bu yüzden bir yanıt göndereceğimi düşündüm.

Box-Muller dönüşümünün bir uygulaması da dahil olmak üzere .NET Random sınıfı için bazı genişletme yöntemleri yaptım . Uzantılar oldukları için, proje dahil olduğu sürece (veya derlenmiş DLL'ye başvurduğunuz sürece), yine de yapabilirsiniz

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

Umarım kimse utanmaz fişe aldırmaz.

Sonuçların örnek histogramı (bunu çizmek için bir demo uygulaması dahildir):

görüntü açıklamasını buraya girin


Uzatma sınıfınızda aradığım birkaç şey var! Teşekkürler!
Thomas

1
NextGaussian yönteminizde küçük bir hatanız var. NextDouble () 0,0'dan büyük veya ona eşit ve 1,0'dan küçük rastgele bir kayan noktalı sayı döndürür. Öyleyse, u1 = 1.0 - NextDouble () .... olmalıdır. Diğer günlük (0) patlayacak
Mitch Wheat

21

Math.NET bu işlevselliği sağlar. Bunu nasıl yapacağınız aşağıda açıklanmıştır:

double mean = 100;
double stdDev = 10;

MathNet.Numerics.Distributions.Normal normalDist = new Normal(mean, stdDev);
double randomGaussianValue=   normalDist.Sample();

Belgeleri burada bulabilirsiniz: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm


Mükemmel cevap! Bu işlev, MathNet.Numerics paketindeki NuGet'te mevcuttur . Kendi yuvarlamak zorunda kalmamak her zaman harikadır.
jpmc26

8

Microsoft Connect'te böyle bir özellik için bir istek oluşturdum. Bu aradığınız bir şeyse, lütfen ona oy verin ve görünürlüğünü artırın.

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

Bu özellik Java SDK'ya dahildir. Uygulanması belgelerin bir parçası olarak mevcuttur ve C # veya diğer .NET dillerine kolayca taşınabilir.

Saf hız arıyorsanız, Zigorat Algoritması genellikle en hızlı yaklaşım olarak kabul edilir.

Yine de bu konuda uzman değilim - RoboCup 3D simüle edilmiş robotik futbol kütüphanem için bir parçacık filtresi uygularken buna ihtiyaç duydum ve bu çerçeveye dahil edilmediğinde şaşırdım.


Bu arada, RandomBox Muller polar yönteminin verimli bir şekilde uygulanmasını sağlayan bir sarmalayıcı burada :

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

Yine de ondan birkaç değer aldım. birisi neyin yanlış olduğunu kontrol edebilir mi?
mk7

@ mk7, sıfır etrafında ortalanmış bir Gauss olasılık fonksiyonu, pozitif değerler vermek kadar negatif değerler de verebilir.
Drew Noakes

Haklısın! Gauss PDF'si olan tipik bir popülasyonda ağırlık listesi almak istediğim için mu'yi 75 [kg olarak] ve sigma'yı 10'a ayarlıyorum. her rastgele ağırlık?
mk7

Tek bir örnekten örnek çizmeye devam edebilirsiniz.
Drew Noakes


4

İşte normal dağıtılmış rastgele değişkenler oluşturmak için başka bir hızlı ve kirli çözüm . Rastgele bir nokta (x, y) çizer ve bu noktanın olasılık yoğunluk fonksiyonunuzun eğrisinin altında olup olmadığını kontrol eder, aksi takdirde tekrarlayın.

Bonus: Sadece yoğunluk fonksiyonunu değiştirerek başka herhangi bir dağılım için (örneğin üstel dağılım veya poisson dağılımı ) rastgele değişkenler oluşturabilirsiniz .

    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 * σ * σ));
    }

Önemli: y aralığını ve σ ve μ parametrelerini seçin, böylece fonksiyonun eğrisi maksimum / minimum noktalarında (örn. X = ortalama) kesilmeyecektir. X ve y aralıklarını , eğrinin sığması gereken bir sınırlayıcı kutu olarak düşünün .


4
Tangenial, ama aslında değişkenler için _sigma veya _phi gibi aptalca bir şey yerine Unicode sembollerini kullanabileceğinizi ilk kez fark ettim ...
Slothario

@Slothario Geliştiricilere her yerde 'aptalca bir şey' kullandıkları için teşekkür ederim: |
user2864740

2

@ Yoyoyoyosef'in cevabını daha da hızlı hale getirerek ve bir sarmalayıcı sınıfı yazarak genişletmek istiyorum. Ortaya çıkan ek yük iki kat daha hızlı anlamına gelmeyebilir, ancak neredeyse iki kat daha hızlı olması gerektiğini düşünüyorum . Yine de iş parçacığı için güvenli değil.

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 ve @ Hameer'in yanıtlarını genişleterek, bir 'Gaussian' sınıfı da uyguladım, ancak bellek alanını basitleştirmek için onu Random sınıfının bir çocuğu yaptım, böylece temel Next (), NextDouble () da diyebilirsiniz. , vb. Gauss sınıfından ve onu işlemek için ek bir Random nesnesi oluşturmak zorunda kalmadan. Ayrıca _available ve _nextgauss global sınıf özelliklerini de elimine ettim, çünkü bu sınıf örnek tabanlı olduğundan onları gerekli görmediğim için, her bir iş parçacığına kendi Gauss nesnesini verirseniz iş parçacığı güvenli olmalıdır. Ayrıca, çalışma zamanı tahsis edilen tüm değişkenleri işlevin dışına taşıdım ve onları sınıf özellikleri yaptım, bu, bellek yöneticisine yapılan çağrıların sayısını azaltacak, çünkü 4 çift teorik olarak nesne yok edilene kadar asla ayrılmamalıdır.

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

Yerel değişkenler de arkadaştır.
user2864740

1

Box-Muller'dan daha iyi performansa ihtiyacınız varsa (yaklaşık% 50-75 daha hızlı), Drew Noakes'in cevabını genişleten Colin Green, burada bulabileceğiniz C # 'da Ziggurat algoritmasının bir uygulamasını paylaştı:

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

Ziggurat, eğriden yeterince uzağa düşen değerleri işlemek için bir arama tablosu kullanır ve bunu hızla kabul eder veya reddeder. Zamanın yaklaşık% 2,5'inde, bir sayının eğrinin hangi tarafında olduğunu belirlemek için daha fazla hesaplama yapmak zorundadır.


0

Infer.NET'i deneyebilirsiniz. Henüz ticari lisanslı değil. İşte bağlantı var

Microsoft araştırmamı geliştiren .NET için olasılıklı bir çerçeve. Bernoulli, Beta, Gamma, Gaussian, Poisson dağıtımları için .NET türleri var ve muhtemelen bazılarını dışarıda bıraktım.

İstediğinizi başarabilir. Teşekkürler.


0

Bu, Box Muller'dan ilham alan basit uygulamam. İhtiyaçlarınıza uyacak şekilde çözünürlüğü artırabilirsiniz. Bu benim için harika çalışsa da, bu sınırlı bir aralık yaklaşımıdır, bu yüzden kuyrukların kapalı ve sonlu olduğunu unutmayın, ancak kesinlikle bunları gerektiği gibi genişletebilirsiniz.

    //
    // 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;
   }
} 

Bu, Box Muller'dan ilham alan basit uygulamam. İhtiyaçlarınıza uyacak şekilde çözünürlüğü artırabilirsiniz. Bu çok hızlı, basit ve işi tamamlamak için yaklaşık Gauss tipi olasılık yoğunluğu fonksiyonuna ihtiyaç duyan sinir ağı uygulamalarım için çalışıyor. Umarım birisinin zamandan ve CPU döngülerinden tasarruf etmesine yardımcı olur. Bu benim için harika çalışsa da, bu sınırlı bir aralık yaklaşımıdır, bu yüzden kuyrukların kapalı ve sonlu olduğunu unutmayın, ancak kesinlikle bunları gerektiği gibi genişletebilirsiniz.
Daniel Howard

1
Daniel, yorumunuzdaki açıklamayı cevabın kendisiyle birleştiren bir düzenleme önerdim. Ayrıca cevabınızdaki gerçek kodu yorumlayan '//' ifadesini de kaldırır. İsterseniz / reddedilirse düzenlemeyi kendiniz yapabilirsiniz :)
mbrig

-1

Olduğunu sanmıyorum. Ve umarım, çerçeve zaten yeterince şişirilmiş olduğundan, bu tür özel işlevler onu daha da doldurmadan olmaz.

Bir göz atın http://www.extremeoptimization.com/Statistics/UsersGuide/ContinuousDistributions/NormalDistribution.aspx ve http://www.vbforums.com/showthread.php?t=488959 olsa üçüncü bir .NET çözümleri için.


7
Gauss dağıtımı ne zamandan beri 'uzmanlaşmıştır'? Diyelim ki AJAX veya DataTables'dan çok daha genel.
TraumaPony

@TraumaPony: Cidden, düzenli olarak AJAX kullanmak yerine daha fazla geliştiricinin Gauss dağıtımını kullanmasını önermeye mi çalışıyorsunuz?
David Arno

3
Muhtemelen; Demek istediğim, çok daha özel olduğu. Yalnızca tek kullanımlık web uygulamaları vardır. Gauss dağıtımlarının inanılmaz sayıda ilgisiz kullanımı vardır.
TraumaPony

@DavidArno, daha az işlevselliğin bir çerçeveyi iyileştirdiğini cidden mi öneriyorsunuz?
Jodrell

1
@Jodrell, spesifik bir örnek vermek gerekirse, MVC'yi ana .NET çerçevesinin bir parçası olmaktan ziyade ayrı bir çerçeve haline getirme kararının iyi bir karar olduğunu düşünüyorum.
David Arno
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.