A técnica da inversão é uma maneira poderosa de gerar variáveis aleatórias (v.a.) a partir de uma distribuição arbitrária, usando números aleatórios uniformes no intervalo \([0, 1)\). A ideia básica é usar a função de distribuição acumulada (CDF) para mapear um número uniforme gerado entre 0 e 1 para o valor correspondente da v.a. discreta.
5.1 Inversa da CDF
O método da inversão recebe esse nome pois seu algoritmo também pode ser caracterizado pela função inversa da CDF. A inversa da CDF (função de distribuição acumulada), também conhecida como a função quantil, é definida da seguinte forma:
Definição: Seja \(F(x)\) a função de distribuição acumulada (CDF) de uma variável aleatória \(X\). A inversa da CDF, denotada por \(F^{-1}(p)\), é definida como:
\[
F^{-1}(p) = \inf \{ x \in \mathbb{R} : F(x) \geq p \}, \quad \text{para } p \in [0, 1]
\]
Em palavras: - A inversa da CDF \(F^{-1}(p)\) mapeia um número \(p\), que representa uma probabilidade acumulada, de volta ao valor \(x\) correspondente da variável aleatória \(X\), tal que a probabilidade acumulada até \(x\) é igual a \(p\). - Isso significa que, se \(p = F(x)\), então \(F^{-1}(p) = x\).
Assim, o menor valor \(x_i\) tal que \(F(x_i) \geq u\) é justamente \(F^{-1}(u)\)
5.2 Geração de Variáveis Aleatórias Discretas Genéricas
Considere uma v.a. discreta \(X\) que assume valores em em \(x_1,x_2,\ldots\). Dadas as probabilidades de cada um desses valores \(p(x_i)\), a CDF \(F(x)\) é definida como:
\[
F(x_i) = \sum_{j=1}^{i} p(x_j)
\]
O algoritmo da inversão para gerar uma variável aleatória discreta genérica é:
Gerar um número aleatório com distribuição uniforme \(u \in [0, 1)\).
Encontrar o menor valor \(x_i\) tal que \(F(x_i) \geq u\).
# Exemplo de valores e probabilidades de uma variável aleatória discretavalores <-c(0, 1, 2, 3, 4, 5, 6)probabilidades <-c(0, 0.1, 0.2, 0.3, 0.25, 0.15, 0) # Calculando a CDFcdf <-cumsum(probabilidades)# Gerando um número aleatório uniformeu <-runif(1)# Encontrando o valor correspondente na CDFvalor_gerado <-NAfor (i inseq_along(valores)) {if (u <= cdf[i]) { valor_gerado <- valores[i]break }}# Ajustando o gráfico para corrigir a visualização da CDF e garantir que os valores estejam corretamente posicionadoslibrary(ggplot2)# Criando um dataframe para os valores e CDFdf <-data.frame(valores = valores, cdf = cdf)# Gráfico da CDF com número aleatório e valor geradoggplot(df, aes(x = valores, y = cdf)) +geom_step(direction ="hv", color ="blue", size =1.5) +geom_hline(yintercept = u, color ="red", linetype ="dashed") +geom_vline(xintercept = valor_gerado, color ="green", linetype ="dashed") +labs(title ="Técnica da Inversão para Geração de Variável Aleatória Discreta",x ="Valores da Variável Aleatória", y ="CDF") +annotate("text", x =max(valores), y = u, label =sprintf("u = %.2f", u), hjust =-0.1, vjust =-1) +annotate("text", x = valor_gerado, y =max(cdf), label =paste("Valor gerado =", valor_gerado), hjust =-0.1, vjust =-0.5) +theme_minimal() +theme(panel.grid =element_blank())
Mostrar código
import numpy as npimport matplotlib.pyplot as plt# Exemplo de valores e probabilidades de uma variável aleatória discretavalores = [0, 1, 2, 3, 4, 5, 6]probabilidades = [0, 0.1, 0.2, 0.3, 0.25, 0.15, 0]# Calculando a CDFcdf = np.cumsum(probabilidades)# Gerando um número aleatório uniformeu = np.random.uniform(0, 1)# Encontre o valor correspondente na CDFvalor_gerado =Nonefor i, valor inenumerate(valores):if u < cdf[i]: valor_gerado = valorbreak# Ajustando o gráfico para corrigir a visualização da CDF e garantir que os valores estejam corretamente posicionadosplt.figure(figsize=(10, 6))# Ajustando o eixo x para que a CDF comece e termine corretamenteplt.step(valores, cdf, label='CDF', color='blue', linewidth=2, where='post')plt.axhline(y=u, color='red', linestyle='--', label=f'Número aleatório u = {u:.2f}')plt.axvline(x=valor_gerado, color='green', linestyle='--', label=f'Valor gerado = {valor_gerado}')plt.title('Técnica da Inversão para Geração de Variável Aleatória Discreta')plt.xlabel('Valores da Variável Aleatória')plt.ylabel('CDF')plt.legend()plt.grid(True)plt.show()
5.3 Prova de que o método funciona
Enunciado. Considere uma v.a. discreta \(X\) com suporte ordenado \(x_1<x_2<\cdots\) e massas \(p_i=\mathbb{P}(X=x_i)\). Defina \(F(x_i)=\sum_{j\le i}p_j\) e \(F(x)=0\) para \(x<x_1\). Seja \(U\sim\mathrm{Unif}(0,1)\) e \[
\tilde{X}=\min\{x_i:\,F(x_i)\ge U\}.
\] Então \(\tilde{X}\) tem a mesma distribuição de \(X\).
Demonstração. Para cada \(i\ge1\), \[
\{\tilde{X}=x_i\}=\{F(x_{i-1})<U\le F(x_i)\},
\] onde \(F(x_0)=0\). Logo, \[
\mathbb{P}(\tilde{X}=x_i)=F(x_i)-F(x_{i-1})=p_i.
\] Portanto, \(\tilde{X}\) reproduz exatamente a PMF desejada.
5.4 Exemplo 1: Geração de uma Bernoulli por inversão
Para \(X\sim\mathrm{Bernoulli}(p)\), temos \(\mathbb P(X=0)=1-p\), \(\mathbb P(X=1)=p\) e
\[
F(0)=1-p,\quad F(1)=1.
\]
Assim, o mesmo da inversão consiste em gerar \(U\sim\mathrm{Unif}(0,1)\) e definir
([<matplotlib.axis.XTick object at 0x7558a291f3b0>, <matplotlib.axis.XTick object at 0x7558a2900ec0>], [Text(0.0, 0, '0'), Text(1.0, 0, '1')])
Mostrar código
plt.xlabel('Valor de X')plt.ylabel('Probabilidade')plt.title(f'Bernoulli(p) com p = {p:.2f} — n = {n}')plt.legend()plt.grid(True, axis='y')plt.show()
5.5 Exemplo 2: Geração de Variáveis Aleatórias com Distribuição Geométrica
A distribuição geométrica modela o número de falhas até o primeiro sucesso em uma sequência de experimentos de Bernoulli. Se a probabilidade de sucesso em cada tentativa é \(p\), a PMF é dada por: \[
P(X = k) = (1 - p)^{k} p \quad \text{para} \quad k = 0, 1, 2 \dots
\] onde \(k\) representa o número de falhas antes do primeiro sucesso.
Vamos agora obter a fórmula da inversa da CDF para a distribuição geométrica foi obtida a partir da função de distribuição acumulada (CDF) da distribuição geométrica:
\[
\begin{aligned}
F(k) & = \mathbb{P}(X \leq k) = \sum_{x=0}^{k}(1 - p)^{x}p \\
&= \frac{p}{1 - p} \sum_{x=0}^{k} (1 - p)^x\\
& = \frac{p}{1 - p} \cdot \frac{(1 - p)(1 - (1 - p)^{k+1})}{p}\\
&= 1 - (1 - p)^{k+1}.
\end{aligned}
\] Queremos encontrar a inversa da CDF, ou seja, a fórmula que, dado um valor \(u\) entre 0 e 1, nos permita calcular o valor \(k\) tal que \(F(k) = u\).
Sabemos que:
\[
u = F(k) = 1 - (1 - p)^{k+1}
\]
Nosso objetivo é resolver essa equação para \(k\). Vamos fazer isso passo a passo.
Começamos isolando o termo \((1 - p)^{k+1}\):
\[
u = 1 - (1 - p)^{k+1}
\]
Subtraindo 1 de ambos os lados:
\[
u - 1 = - (1 - p)^{k+1}
\]
Multiplicando ambos os lados por \(-1\):
\[
1 - u = (1 - p)^{k+1}
\]
Agora aplicamos o logaritmo natural (log base \(e\)) em ambos os lados para resolver \(k\):
\[
\log(1 - u) = \log((1 - p)^{k+1})
\]
Usando a propriedade dos logaritmos que permite trazer o expoente \(k\) para frente:
\[
\log(1 - u) = (k+1) \cdot \log(1 - p)
\]
Agora, isolamos \(k\) e levamos em conta que ele deve ser inteiro, temos:
# Função para gerar a inversa da CDF para a distribuição geométricainversa_cdf_geometrica <-function(p, u) {# k = falhas antes do 1º sucesso k <-ceiling(log1p(-u) /log1p(-p)) -1Las.integer(k)}# Parâmetro p da distribuição geométricap <-0.5# Gerando 1000 números uniformemente distribuídosuniformes <-runif(1000)# Gerando a variável aleatória geométrica correspondente para cada número uniformegeometricas <-sapply(uniformes, inversa_cdf_geometrica, p = p)# Plotando um histograma das variáveis geométricas geradaslibrary(ggplot2)df <-data.frame(geometricas = geometricas)ggplot(df, aes(x = geometricas)) +geom_histogram(bins =max(geometricas) +1, color ="black", fill ="skyblue", boundary =0, closed ="left") +labs(title ="Histograma de Variáveis Aleatórias Geométricas Usando a Inversa da CDF",x ="Valor da Variável Aleatória Geométrica", y ="Frequência") +theme_minimal() +theme(panel.grid.major =element_blank())
Mostrar código
# Função para calcular a CDF da distribuição geométricacdf_geometrica <-function(k, p) {1- (1- p)^(k +1)}# Gerando valores de k para plotar a CDFk_values <-0:20cdf_values <-sapply(k_values, cdf_geometrica, p = p)# Plotando a CDF da distribuição geométricadf_cdf <-data.frame(k_values = k_values, cdf_values = cdf_values)ggplot(df_cdf, aes(x = k_values, y = cdf_values)) +geom_step(direction ="hv", color ="blue", size =1.5) +labs(title ="CDF da Distribuição Geométrica (p = 0.5)",x ="k (Número de tentativas até o primeiro sucesso)", y ="F(k)") +theme_minimal() +theme(panel.grid.major =element_blank())
Mostrar código
import numpy as npimport math as mathimport matplotlib.pyplot as plt# Função para gerar a inversa da CDF para a distribuição geométricadef inversa_cdf_geometrica(p, u):# k = falhas antes do 1º sucesso k = math.log1p(-u) / math.log1p(-p)returnint(k)# Parâmetro p da distribuição geométricap =0.5# Gerando 1000 números uniformemente distribuídosuniformes = np.random.uniform(0, 1, 1000)# Gerando a variável aleatória geométrica correspondente para cada número uniformegeometricas = [inversa_cdf_geometrica(p, u) for u in uniformes]# Plotando um histograma das variáveis geométricas geradasplt.figure(figsize=(10, 6))plt.hist(geometricas, bins=range(0, max(geometricas) +2), # inclui o último intervalo edgecolor='black', align='left')plt.title('Histograma de Variáveis Aleatórias Geométricas Usando a Inversa da CDF')plt.xlabel('Valor da Variável Aleatória Geométrica')plt.ylabel('Frequência')plt.grid(True)plt.show()
Mostrar código
# Calculando a CDF para a distribuição geométricadef cdf_geometrica(k, p):return1- (1- p)**k# Gerando valores de k para plotar a CDFk_values = np.arange(1, 21)cdf_values = [cdf_geometrica(k, p) for k in k_values]# Plotando a CDF da distribuição geométricaplt.figure(figsize=(10, 6))plt.step(k_values, cdf_values, where='post', color='blue', label='CDF Geométrica', linewidth=2)plt.title('CDF da Distribuição Geométrica (p = 0.5)')plt.xlabel('k (Número de tentativas até o primeiro sucesso)')plt.ylabel('F(k)')plt.grid(True)plt.legend()plt.show()
5.6 Exemplo 3: Geração de Variáveis Aleatórias com Distribuição Poisson
A distribuição de Poisson é usada para modelar o número de eventos que ocorrem em um intervalo de tempo ou espaço fixo, onde os eventos ocorrem com uma taxa constante \(\lambda\) e de forma independente.
A função de probabilidade de massa (PMF) da distribuição de Poisson é dada por:
A distribuição de Poisson tem uma fórmula recursiva que pode ser usada para calcular as probabilidades de forma mais eficiente. Em vez de recalcular a probabilidade \(P(X = k)\) a cada vez, podemos usar a seguinte relação recursiva:
Essa relação recursiva permite gerar variáveis aleatórias de Poisson sem precisar calcular fatoriais repetidamente, o que é mais eficiente para grandes valores de \(\lambda\) ou grandes números de eventos \(k\).
5.6.1 Técnica da Inversão Usando a Fórmula Recursiva
Para gerar uma variável aleatória de Poisson usando a técnica da inversão e a fórmula recursiva, o processo é o seguinte:
Seja \(U \sim \text{Unif}(0,1)\)
Faça \(i = 0\), \(p = e^{-\lambda}\) e \(F = p\)
Se \(U \leq F\), faça \(X = i\) e pare.
Senão, atualize \(p = \frac{\lambda p}{i + 1}\), \(F = F + p\) e \(i = i + 1\)
# Função para gerar a inversa da CDF para a distribuição Poisson usando a técnica de inversão e a fórmula recursivainversa_cdf_poisson_recursiva <-function(lam, u) { k <-0 p <-exp(-lam) # P(X=0) F_acm <- p # Iniciamos com a probabilidade P(X=0)# Continuamos somando até que F >= uwhile (u > F_acm) { k <- k +1 p <- p * lam / k # Atualiza a probabilidade recursivamente para o próximo valor F_acm <- F_acm + p }return(k)}# Parâmetro lambda da distribuição Poissonlam <-3# Gerando 1000 números uniformemente distribuídosuniformes <-runif(1000)# Gerando a variável aleatória Poisson correspondente para cada número uniformepoisson_vars <-sapply(uniformes, inversa_cdf_poisson_recursiva, lam = lam)# Plotando o histograma das variáveis Poisson geradaslibrary(ggplot2)df <-data.frame(poisson_vars = poisson_vars)ggplot(df, aes(x = poisson_vars)) +geom_histogram(bins =max(poisson_vars) +1, color ="black", fill ="skyblue", boundary =0, closed ="left") +labs(title ="Histograma de Variáveis Aleatórias Poisson Usando a Fórmula Recursiva (λ = 3)",x ="Valor da Variável Aleatória Poisson", y ="Frequência") +theme_minimal() +theme(panel.grid.major =element_blank())
Mostrar código
# Função para calcular a CDF da distribuição Poissoncdf_poisson <-function(k, lam) { cdf <-0 p <-exp(-lam) # P(X=0)for (i in0:k) { cdf <- cdf + p # Adiciona a probabilidade à CDFif (i < k) { p <- p * lam / (i +1) # Atualiza a probabilidade recursivamente } }return(cdf)}# Gerando valores de k para a CDFk_values <-0:14cdf_values <-sapply(k_values, cdf_poisson, lam = lam)# Plotando a CDF da distribuição Poissondf_cdf <-data.frame(k_values = k_values, cdf_values = cdf_values)ggplot(df_cdf, aes(x = k_values, y = cdf_values)) +geom_step(direction ="hv", color ="blue", size =1.5) +labs(title ="CDF da Distribuição Poisson Usando a Fórmula Recursiva (λ = 3)",x ="k (Número de eventos)", y ="F(k)") +theme_minimal() +theme(panel.grid.major =element_blank())
Mostrar código
import numpy as npimport matplotlib.pyplot as pltimport math# Função para gerar a inversa da CDF para a distribuição Poisson usando a técnica de inversão e a fórmula recursivadef inversa_cdf_poisson_recursiva(lam, u): k =0 p = math.exp(-lam) # P(X=0) F = p # Iniciamos com a probabilidade P(X=0)# Continuamos somando até que F >= uwhile u > F: k +=1 p = p * lam / k # Atualiza a probabilidade recursivamente para o próximo valor F += preturn k# Parâmetro lambda da distribuição Poissonlam =3# Gerando 1000 números uniformemente distribuídosuniformes = np.random.uniform(0, 1, 1000)# Gerando a variável aleatória Poisson correspondente para cada número uniformepoisson_vars = [inversa_cdf_poisson_recursiva(lam, u) for u in uniformes]# Plotando o histograma das variáveis Poisson geradasplt.figure(figsize=(10, 6))plt.hist(poisson_vars, bins=range(0, max(poisson_vars) +1), color='skyblue', edgecolor='black', align='left')plt.title('Histograma de Variáveis Aleatórias Poisson Usando a Fórmula Recursiva (λ = 3)')plt.xlabel('Valor da Variável Aleatória Poisson')plt.ylabel('Frequência')plt.grid(True)plt.show()
Mostrar código
# Calculando a CDF da distribuição Poissondef cdf_poisson(k, lam): cdf =0 p = math.exp(-lam) # P(X=0)for i inrange(k+1): cdf += p # Adiciona a probabilidade à CDFif i < k: # Atualiza a probabilidade recursivamente p = p * lam / (i +1)return cdf# Gerando valores de k para a CDFk_values = np.arange(0, 15)cdf_values = [cdf_poisson(k, lam) for k in k_values]# Plotando a CDF da distribuição Poissonplt.figure(figsize=(10, 6))plt.step(k_values, cdf_values, where='post', color='blue', label='CDF Poisson', linewidth=2)plt.title('CDF da Distribuição Poisson Usando a Fórmula Recursiva (λ = 3)')plt.xlabel('k (Número de eventos)')plt.ylabel('F(k)')plt.grid(True)plt.legend()plt.show()
5.7 Exercícios
Exercício 1. Seja \(X\) uma v.a. tal que \(\mathbb P(X=1)=0.3,\mathbb P(X=3)=0.1\) e \(\mathbb P(X=4)=0.6\).
Escreva um pseudo-algoritmo para gerar um valor de \(X\).
Implemente uma função para gerar \(n\) valores de \(X\).
Compare a distribuição das frequências obtidas na amostra simulada com as probabilidades reais.
Implemente um algoritmo para gerar uma amostra de tamanho \(n\) da distribuição mistura de uma Poisson e de uma Geométrica com base nas funções implementadas nos exemplos (2) e (3).