Pergunta

Existe uma classe na biblioteca padrão do .NET que me dá a funcionalidade para criar variáveis ??aleatórias que seguem distribuição de Gauss?

Foi útil?

Solução

sugestão de usar transformar um Box-Muller de Jarrett é bom para uma solução rápida e suja. Uma implementação simples:

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)

Outras dicas

Esta questão parece ter movido no topo do Google para a geração .NET Gaussian, então eu percebi que eu postar uma resposta.

Eu fiz alguns métodos de extensão para a classe .NET aleatória, incluindo uma implementação de o Box-Muller transformar. Como eles são extensões, desde que o projeto está incluído (ou você faz referência a DLL compilado), você ainda pode fazer

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

espero que ninguém mentes o plug descarado.

histograma Amostra de resultados (um aplicativo de demonstração para desenhar isso está incluído):

enter descrição da imagem aqui

Math.NET oferece essa funcionalidade. Veja como:

double mean = 100;
double stdDev = 10;

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

Você pode encontrar a documentação aqui: http://numerics.mathdotnet.com/api/MathNet.Numerics.Distributions/Normal.htm

Eu criei um pedido de recurso tal no Microsoft Connect. Se isso é algo que você está procurando, por favor voto para ele e aumentar a sua visibilidade.

https://connect.microsoft. com / VisualStudio / feedback / details / 634346 / guassian normal-distribuição-random-números

Este recurso está incluído no Java SDK. A sua implementação está disponível como parte de documentação e é facilmente portado para C # ou outras linguagens .NET.

Se você está à procura de velocidade pura, então a Zigorat Algoritmo é geralmente reconhecido como o abordagem mais rápida.

Eu não sou um especialista sobre este tema - embora me deparei com a necessidade para este durante a implementação de um filtro de partículas para o meu RoboCup 3D simulado robótico biblioteca de futebol e foi surpreendido quando este não foi incluído no quadro.


Enquanto isso, aqui está um invólucro para Random que fornece uma implementação eficiente do método polar 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 também afirma implementar "geradores aleatórios não uniformes (normal, poisson, binomial, ...)".

Aqui está uma outra solução rápida e suja para a geração de variáveis ??aleatórias que são normais distribuídos . Ele desenha algum ponto aleatório (x, y) e verifica se este ponto está sob a curva de sua função densidade de probabilidade, caso contrário repetir.

Bônus: Você pode gerar variáveis ??aleatórias para qualquer outra distribuição (por exemplo, o exponencial distribuição ou poisson distribuição) apenas substituindo a função de densidade.

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

Importante: Selecione o intervalo de y e os parâmetros s e µ para que a curva da função não é de corte para ele do máximo / pontos de mínimo (por exemplo, em x = significativo). Pense nos intervalos de x e y como uma caixa delimitadora, em que a curva deve caber dentro.

Eu gostaria de expandir @ resposta yoyoyoyosef de, tornando-a ainda mais rápido, e escrever uma classe wrapper. A sobrecarga incorridos pode não significar duas vezes mais rápido, mas eu acho que deveria ser quase duas vezes mais rápido. Ele não é thread-safe, apesar de tudo.

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

Expandindo resposta de Drew Noakes, se você precisar de um melhor desempenho do que a caixa-Muller (cerca de 50-75% mais rápido), Colin Verde compartilhou uma implementação do algoritmo de Ziggurat em C #, que você pode encontrar aqui:

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

Zigurate usa uma tabela de pesquisa para lidar com valores que se enquadram suficientemente longe da curva, o que ele vai rapidamente aceitar ou rejeitar. Cerca de 2,5% do tempo, tem que fazer mais cálculos para determinar qual dos lados da curva é um número no.

A expansão fora de @Noakes e @ respostas de Hameer, eu também implementou uma classe 'Gaussian', mas para o espaço de memória simplifica, eu fiz isso uma criança da classe Random para que você também pode ligar para o básico Next (), NextDouble (), etc, a partir da classe de Gauss assim, sem ter de criar um objecto aleatório adicional para lidar com ele. Eu também eliminou as propriedades da classe _available e _nextgauss globais, como eu não vê-los como necessário, pois esta classe é baseada instância, deve ser thread-safe, se você dá a cada thread seu próprio objeto de Gauss. Eu também mudou-se todas as variáveis ??tempo de execução alocados fora da função e os pôs por propriedades de classe, isso irá reduzir o número de chamadas para o gerenciador de memória desde os 4 duplos teoricamente deveria nunca será de-alocados até que o objeto é destruído.

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

Você poderia tentar Infer.NET. Não é comercial ainda licenciado embora. Aqui está lá ligação

É uma estrutura probabilística para .NET desenvolveu minha pesquisa Microsoft. Eles têm .NET tipos de distribuições de Bernoulli, Beta, Gamma, Gaussian, Poisson, e provavelmente um pouco mais eu deixei de fora.

Pode realizar o que deseja. Obrigado.

Esta é a minha simples Box Muller inspirado implementação. Você pode aumentar a resolução para atender às suas necessidades. Embora isso funciona muito bem para mim, esta é uma aproximação alcance limitado, de modo a manter em mente as caudas estão fechados e finito, mas certamente você pode expandi-los, conforme necessário.

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

Eu não acho que há. E eu realmente espero que não é, como o quadro já é bastante inchado, sem essa funcionalidade especializada preenchê-lo ainda mais.

Dê uma olhada http://www.extremeoptimization.com/Statistics /UsersGuide/ContinuousDistributions/NormalDistribution.aspx e http: //www.vbforums .com / showthread.php? t = 488959 por terceiros soluções partido .NET embora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top