<jupyter_start><jupyter_text>UNIVERSIDAD NACIONAL DE CÓRDOBA Fa.M.A.F – Observatorio Astronómico  Licenciatura en Astronomía  <NAME>  Astrometría 2020  Práctico N° 2  Actividad 2  lntroducción Una variable aleatoria normal estándar es aquella que tiene una función de densidad de probabilidad:$$ f_{X}(x) = (1/\sqrt{ 2\pi }) * e^{-x^{2}/2} $$es decir, N(µ = 0, σ = 1). Existen varios métodos para generar esta variable en una computadora, que tienen distintas eficiencias, lo cual surge del hecho de que la cantidad de valores generados es menor que la cantidad de variables aleatorias uniformes que se usan. Uno de los métodos más eficientes es el método de Box-Muller. Este método permite obtener dos variables aleatorias normales estándar a partir de dos variables aleatorias uniformes, usando las transformaciones de Box-Muller.El objetivo de este trabajo es: - Explicar el desarrollo teórico del método- Desarrollar un programa para generar variables aleatorias normales utilizando el método de Box-Muller- Mejorar la eficiencia del código generando pares de números aleatorios (X,Y) dentro del círculo de radio unidad  Método de Box-Muller para generar una V.A. con distribución normal Como se menconó anteriormente, el algoritmo Box-Muller se puede utilizar para convertir dos conjuntos de números aleatorios con distribuciones uniformes en dos conjuntos de números aleatorios con distribuciones gaussianas. Este algoritmo no utiliza ningún método de aproximación. En cambio, hace uso de la integral gaussiana.Sean X e Y dos VA normales estándar independientes, y sean las nuevas variables definidas por:$$ R^{2} = X^{2} + Y^{2} $$$$ tan(\theta) = X / Y $$Como X e Y son independientes, la función de densidad de probabilidad conjunta f(X, Y) satisface que:$$ f(X, Y) = f(X)*f(Y) $$es decir, $$f(X, Y) = \frac {1} {\sqrt{ 2\pi }}e^{\frac{-x^2} {2}} \frac {1} {\sqrt{ 2\pi }}e^{\frac{-y^2} {2}}$$$$ = \frac {1} {\sqrt{ 2\pi }}e^{\frac{-(x^2 + y^2)} {2}} $$$$ = \frac {1} {\sqrt{ 2\pi }}e^{\frac{-R^2} {2}} $$La función de densidad de probabilidad conjunta de $R^2$ y $ \theta $ está dada por el **teorema del cambio de variables**:$$ f_{\overline {Y}} (\overline {y}) = \int_{-\infty}^{\infty} f_{\overline {X}} (\overline {x}) \prod_{i = 1}^m \delta(y_{i} -\varphi_{i}(\overline {x}))d\overline {x}$$Sea el siguiente cambio de variables:$$ \varphi_{1}(R^2, \theta) = x^2 + y^2 $$$$ \varphi_{2}(R^2, \theta) = \arctan (\frac{y} {x}) $$$$ f(R^2, \theta) = \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} f(x,y) \delta(R^2 -\varphi_{1}(x,y))\delta(\theta -\varphi_{2}(x,y))dxdy$$$$ f(R^2, \theta) = \frac{1} {2} \frac{1} {2\pi}e^{\frac{-R^2} {2}} $$Notar que el factor 1/2 proviene de la inversa del Jacobiano de la transformación realizada, es decir el determinante de las derivadas parciales de R^2 y 0 con respecto a x e y. Luego, el resultado obtenido en la última ecuación, equivale al producto de una densidad exponencial con media 2 y unauniforme entre 0 y 2π. Por lo tanto, R^2 y θ son independientes. De esta forma es posible sortear números θ y R^2 con esasdistribuciones, y hacer la transformación de variables para obtener variables X e Y que tendrán una distribución normal estándar cada una de ellas. Pasos a seguir para aplicar el método -  Primero se generan dos números aleatorios u1 y u2. -  Luego, se define que:$$ R^2 = -2 log(u1) $$$$ \theta = 2\pi *  u2 $$- Finalmente, se aplican las **transformaciones de Box-Muller**:$$ x = R*cos(\theta) = \sqrt{ -2 log(u1) } * cos( 2\pi u2) $$$$ y = R*sin(\theta) = \sqrt{ -2 log(u1) } * sin( 2\pi u2) $$  Aplicación del método B-M<jupyter_code>#Primero se importan las librerías necesarias para trabajar
import numpy as np
import matplotlib.pyplot as plt
import random
import math
import seaborn as sns          
sns.set()         
from scipy.stats import poisson
import statistics
#Se define una función, que crea las variables aleatorias normales usando el método desarrollado

def Box_Muller1(n=1000):                    # n define la cantidad de variables que se desean 
    lx = []
    ly = []
    for i in range(n):
        u1 = random.random()
        u2 = random.random()
        x = math.sqrt(-2 * math.log(u1)) * math.cos(2*math.pi*u2)
        y = math.sqrt(-2 * math.log(u1)) * math.sin(2*math.pi*u2)
        lx.append(x)
        ly.append(y)
    return(lx,ly)
# Se grafican los resultados obtenidos 
x, y = Box_Muller1()
plt.title('Valores de $ X $ e $ Y $')
plt.plot(x, y, 'og')
plt.xlabel('$X$')
plt.ylabel('$Y$')
plt.show()
#Con el siguiente gráfico se puede ver las distribuciones de las variables X e Y

sns.jointplot(x, y, kind='scatter', color = 'greenyellow')<jupyter_output><empty_output><jupyter_text>Lamentablemente, el uso de las transformaciones de Box-Muller para generar un par de variables aleatorias normales e independientes no es eficiente desde el punto de vista computacional, ya que calcular las funciones trigonométricas seno y coseno lleva tiempo. Sin embargo, hay una manera de evadir esta dificultad mediante un cálculo indirecto del seno y coseno de un ángulo aleatorio. Ésta forma consiste en generar pares de números aleatorios dentro de un círculo de radio unidad. A continuación se presenta ésta mejora, aplicándola al código de generación ya creado.<jupyter_code>#En primer lugar, se crea una función que generará las variables aleatorias de mejor manera

def Box_Muller2(n=1000):
    lx = []
    ly = []
    for i in range(n):
        u1 = random.random()        #Notar que si u es uniforme en (0,1), 2u e suniforme en (0,2) y 2u-1 es uniforme en (-1,1)
        u2 = random.random()               
        v1 = 2*u1 - 1               #v1 y v2 estan distribuidas uniformente en un cuadrado de área 4 con centro en (0,0)
        v2 = 2*u2 - 1
        s = v1**2 + v2**2           # s = R^2
        if s > 1:                   #Con este if se limita a los valores de v1 y v2 al círculo unidad
             None
        else:
            x = math.sqrt(-2 * math.log(s)/s) * v1
            y = math.sqrt(-2 * math.log(s)/s) * v2
            lx.append(x)
            ly.append(y)
    return(lx,ly)

x, y = Box_Muller2()
plt.title('Valores de $ X $ e $ Y $')
plt.plot(x, y, 'or')
plt.xlabel('$X$')
plt.ylabel('$Y$')
plt.show()
#Con el siguiente gráfico se puede ver las distribuciones de las variables X e Y

sns.jointplot(x, y, kind='scatter', color = 'yellowgreen')<jupyter_output><empty_output><jupyter_text>Como se puede ver, las variables aleatorias obtenidas, con ambos métodos, están uniformemente distribuídas y sus distribuciones son similares. Es decir que a simple vista no se puede notar una 'diferencia' al variar el método. Se calculará a continuación el tiempo de cómputo de cada método para así evaluar su eficiencia.<jupyter_code>#Para el método 1 

Tiempo = %timeit -o Box_Muller1()

#Se guardan los resultados en una lista
lT = Tiempo.all_runs
lT
#Se calcula un promedio de los 7 promedios de tiempos obtenidos en la celda anterior 
tm = statistics.mean(lT)
tm
#Para Box_Muller2

Tiempo2 = %timeit -o Box_Muller2()
lT2 = Tiempo2.all_runs
lT2
tm2 = statistics.mean(lT2)
tm2<jupyter_output><empty_output><jupyter_text>En primera instancia, los valores obtenidos son muy similares. Esto se debe a que la cantidad de variables pedidas, n, es aceptable y no se diferencian tanto los tiempos requeridos por cada método. A continuación se modificará n por 10000 y se verá que ocurre con los t.<jupyter_code>Tiempo1 = %timeit -o Box_Muller1(n=1000000)

Tiempo2 = %timeit -o Box_Muller2(n=1000000)<jupyter_output>3.84 s ± 27.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
{'fraction_non_alphanumeric': 0.11131603214332762, 'fraction_numerical': 0.023185351073639837, 'mean_word_length': 3.7302180685358257, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '169797', 'license': 'MIT', 'n_tokens_mistral': 2795, 'n_tokens_neox': 2708, 'n_words': 1002, 'path': 'P2-Ejercicio7.ipynb', 'repo_name': 'MartinaTapia/astrometria_guia2', 'size': '7598'}