Gere números aleatórios a partir da "distribuição uniforme inclinada" da teoria matemática

9

Para alguma finalidade, eu preciso gerar números aleatórios (dados) a partir da distribuição "uniforme inclinado". A "inclinação" desta distribuição pode variar em algum intervalo razoável e, em seguida, minha distribuição deve mudar de uniforme para triangular com base na inclinação. Aqui está minha derivação:

insira a descrição da imagem aqui

Vamos simplificar e gerar os dados de a (azul, vermelho é distribuição uniforme). Para obter a função de densidade de probabilidade da linha azul, preciso apenas da equação dessa linha. Portanto:0B

f(x)=tg(φ)x+Y(0)

e desde (foto):

tg(φ)=1/BY(0)B/2Y(0)=1Btg(φ)B2

Nós temos que:

f(x)=tg(φ)x+(1Btg(φ)B2)

Como é PDF, CDF é igual a:f(x)

F(x)=tg(φ)x22+x(1Btg(φ)B2)

Agora vamos fazer um gerador de dados. A idéia é que, se eu consertar , números aleatórios podem ser computados se obtivermos números de de uma distribuição uniforme, conforme descrito aqui . Portanto, se eu precisar de 100 números aleatórios da minha distribuição com fixo , então para qualquer da distribuição uniforme há da "distribuição inclinada" e podem ser computados como:φ,Bx(0,1)φ,Bti(0,1)xix

tg(φ)xi22+xi(1Btg(φ)B2)ti=0

A partir dessa teoria, criei código em Python que se parece com:

import numpy as np
import math
import random
def tan_choice():
    x = random.uniform(-math.pi/3, math.pi/3)
    tan = math.tan(x)
    return tan

def rand_shape_unif(N, B, tg_fi):
    res = []
    n = 0
    while N > n:
        c = random.uniform(0,1)
        a = tg_fi/2
        b = 1/B - (tg_fi*B)/2
        quadratic = np.poly1d([a,b,-c])
        rots = quadratic.roots
        rot = rots[(rots.imag == 0) & (rots.real >= 0) & (rots.real <= B)].real
        rot = float(rot)
        res.append(rot)
        n += 1
    return res

def rand_numb(N_, B_):
    tan_ = tan_choice()
    res = rand_shape_unif(N_, B_, tan_)
    return res

Mas os números gerados rand_numbsão muito próximos de zero ou de B (que eu defini como 25). Não há variação, quando eu gero 100 números, todos eles são próximos de 25 ou todos são próximos de zero. Em uma corrida:

num = rand_numb(100, 25)
numb
Out[140]: 
[0.1063241766836174,
 0.011086243095907753,
 0.05690217839063588,
 0.08551031241199764,
 0.03411227661295121,
 0.10927087752739746,
 0.1173334720516189,
 0.14160616846114774,
 0.020124543145515768,
 0.10794924067959207]

Portanto, deve haver algo muito errado no meu código. Alguém pode me ajudar com minha derivação ou código? Estou louco por isso agora, não vejo nenhum erro. Suponho que o código R me dê resultados semelhantes.

Robert
fonte
2
Se você só precisa gerar números aleatórios, não precisa calcular a distribuição. Basta jogar dardos na foto e reter as coordenadas x, mas quando um dardo cair no triângulo esquerdo com o rótulo " ", altere a coordenada de para . Por exemplo, forneça quaisquer valores para e (um parâmetro real que, quando dados entre e , produzem suas distribuições) e definido como o número de valores aleatórios necessários. Aqui está o código:ϕxBxBtheta11nRx<-runif(n,-1,1);x<-(ifelse(runif(n,-1,1)>theta*x,-x,x)+1)*(B/2)
whuber

Respostas:

9

Sua derivação está bem. Observe que para obter uma densidade positiva em , você deve restringir No seu código , você deve entre , é aí que seu código falha.(0,B)

B2tanϕ<2.
B=25ϕ±tan12625

Você pode (e deve) Evite usar um solucionador quadrático e, em seguida, selecione as raízes entre 0 e . A equação polinomial quadrática em a ser resolvida é com Pela construção e ; também aumenta em .Bx

F(x)=t
F(0)=0F(B)=1F(0,B)
F(x)=12tanϕx2+(1BB2tanϕ)x.
F(0)=0F(B)=1F(0,B)

A partir disso, é fácil ver que, se , a parte da parábola em que estamos interessados ​​faz parte do lado direito da parábola, e a raiz a manter é a mais alta das duas raízes, que é Pelo contrário, se , a parábola está de cabeça para baixo e temos interesse em sua esquerda parte. A raiz a manter é a mais baixa. Levando em consideração o sinal de , parece que essa é a mesma raiz (ou seja, aquela com ) que no primeiro caso.x = 1tanϕ>0tanϕ<0tanϕ+

x=1tanϕ(B2tanϕ1B+(B2tanϕ1B)2+2tanϕt.)
tanϕ<0tanϕ+Δ

Aqui está um código R.

phi <- pi/8; B <- 2
f <- function(t) (-(1/B - 0.5*B*tan(phi)) + 
       sqrt( (1/B - 0.5*B*tan(phi))**2 + 2 * tan(phi) * t))/tan(phi)
hist(f(runif(1e6)))

histogramm 1

E com :ϕ<0

phi <- -pi/8
hist(f(runif(1e6)))

insira a descrição da imagem aqui

Elvis
fonte
11
Cometi um erro, porque coloquei meu ângulo fora dos limites, entendi. Mas sua explicação sobre por que eu deveria evitar usar o solucionador numérico de ainda está nebulosa para mim. Você pode tentar explicar mais, por favor? Eu adoraria obtê-lo. F(x)
Robert
@ Robert Acho que seu código funciona bem se o valor de estiver correto. No entanto, impede que você encontre problemas em potencial (e se nenhuma solução estiver entre 0 e ? Ou se as duas soluções estiverem? Ou se não houver uma solução real?). Vale a pena o trabalho adicional para evitar o uso do solucionador pronto. BϕB
Elvis