Está en la página 1de 6

tarea08_solucion

November 27, 2020

El puntaje de la tarea se divide de igual manera entre todas las preguntas.


[1]: %matplotlib inline
from matplotlib import pyplot as plt
import numpy as np

Primero cargamos los datos:


[2]: x, y, y_err = np.loadtxt('datos.txt', unpack=True)

1) Graficar, usando plt.errorbar (o, preferentemente, su versión orientada a objetos),


los datos entregados en datos.txt
[3]: fig, ax = plt.subplots()
ax.errorbar(x, y, y_err, fmt='o')
ax.set_xlabel('x')
ax.set_ylabel('y')

[3]: Text(0, 0.5, 'y')

1
2) Calcular χ2 para una grilla de parámetros a y b, empezando por los rangos

a ∈ [7, 8]b ∈ [0.5, 1.2]

Para calcular χ2 para cada valor en esta grilla deberán usar sólo operaciones vectoriales.
No se permiten ciclos for/while en esta tarea. Recuerden que para esto pueden usar
np.meshgrid o agregar dimensiones vacías a los arreglos, por ejemplo. Recuerden usar
distintos tamaños para los rangos en a y b para poder distinguirlos fácilmente cuando
vayan revisando su código.
Empezamos por definir los rangos en a y b:
[30]: a = np.linspace(7, 8, 100)
b = np.linspace(0.5, 1.2, 90)

y luego una grilla de predicciones para cada par de valores:


[31]: y_model = a[:,None] + b[:,None,None]*x
y_model.shape

[31]: (90, 100, 50)

Como se puede comprobar a partir de los tamaños, las tres dimensiones corresponden a b, a, y la
predicción de yi para cada par (a,b) (hay 50 datos en datos.txt). La grilla de χ2 es entonces

[32]: chi2 = np.sum((y-y_model)**2/y_err**2, axis=2)


chi2.shape

[32]: (90, 100)

3) Entregar el valor de a y b que minimiza χ2 , y el valor χ2min . Sugerencia: Si usan


argmin para encontrar χ2min , el índice será sobre el arreglo χ2 aplanado. Pueden crear
grillas para los rangos en a y b como vimos en clases, pero tengan cuidado con el orden
de las dimensiones!
Para asegurarnos que los índices coinciden, podemos crear grillas y aplanarlas todas con el mismo
procedimiento, por ejemplo (también podríamos haber aplanado grillas en a y b al comienzo).

[33]: j = np.argmin(chi2.reshape(-1))
print(f'El mínimo de chi2 es {chi2.min():.2f} y ocurre en j={j}')

El mínimo de chi2 es 39.94 y ocurre en j=5060


Creamos las grillas y nos aseguramos que tengan la misma forma que chi2:
[34]: agrid, bgrid = np.meshgrid(a, b)
agrid.shape, bgrid.shape

2
[34]: ((90, 100), (90, 100))

Ahora sólo necesitamos aplanarlas de la misma manera:


[35]: abest = agrid.reshape(-1)[j]
bbest = bgrid.reshape(-1)[j]

De manera que los valores de a y b que minimizan χ2 son


[36]: print(f'a_best = {abest:.2f}')
print(f'b_best = {bbest:.2f}')

a_best = 7.61
b_best = 0.89
4) Calcular los parámetros a y b de mayor probabilidad siguiendo el cálculo matri-
cial desarrollado, incluyendo la matriz de covarianza. Imprimir ambos resultados.
¿Coinciden los dos procedimientos? ¿Qué ventajas ofrece el segundo método?
y
5) Calcular la matriz de covarianza ΣΘ , e imprimir la incerteza en cada uno de los
parámetros a y b.
Siguiendo el enunciado, definimos las matrices Y y M :
[37]: Y = y
M = np.vstack([np.ones(x.size), x]).T
Y.shape, M.shape

[37]: ((50,), (50, 2))

La matriz de covarianza es
[38]: C = y_err**2 * np.eye(y.size)
C.shape

[38]: (50, 50)

puesto que C es diagonal, la inversa es simple 1/C para cada elemento:

[39]: Cinv = 1 / y_err**2 * np.eye(y.size)

Podemos comprobar que este es el caso:


[40]: np.allclose(Cinv, np.linalg.inv(C))

[40]: True

La matriz de covarianza de los parámetros, ΣΘ , es

3
[41]: Sigma_Theta = np.linalg.inv(np.dot(M.T, np.dot(Cinv, M)))
Sigma_Theta

[41]: array([[ 0.05027995, -0.00725228],


[-0.00725228, 0.00128337]])

y la matriz de parámetros, Θ, es
[16]: Theta = np.dot(Sigma_Theta, np.dot(M.T, np.dot(Cinv, Y)))
Theta

[16]: array([7.59867088, 0.89430915])

Por lo tanto, los parámetros que maximizan la probabilidad, y sus incertezas, son
[17]: a_mat, b_mat = Theta
a_err, b_err = np.diag(Sigma_Theta)**0.5
print(f'a = {a_mat:.2f} +/- {a_err:.2f}')
print(f'b = {b_mat:.2f} +/- {b_err:.2f}')

a = 7.60 +/- 0.22


b = 0.89 +/- 0.04
consistente con los resultados anteriores. La ventaja de este método es que no tuvimos que definir
los rangos de a y b a priori, y que las incertezas en estos parámetros se obtienen sin costo adicional.
Además, la precisión en a y b en el primer caso depende del número de elementos con que creamos
la grilla.
Por último, podemos comprobar que el mínimo de χ2 coincide con el valor calculado arriba:
[18]: (Y-Theta.dot(M.T)).T.dot(Cinv.dot(Y-Theta.dot(M.T)))

[18]: 39.938483095552314

6) Mostrar en otro gráfico los valores de χ2 para la grilla de parámetros a y b, con


un mapa de colores y una barra de colores asociada, identificando los valores preferi-
dos para estos parámetros siguiendo ambos procedimientos (con una leyenda para
distinguirlos), además de contornos en los valores χ2min + (2.28, 5.99). Dentro de estos
contornos se contienen el 68% y el 95% de la probabilidad conjunta para a y b, re-
spectivamente. (El ancho del primer contorno en las direcciones horizontal y vertical
corresponde aproximadamente a las incertezas calculadas con ΣΘ .)
Los valores reales de los parámetros a y b con los que se generaron los datos son

a = 7.46 | b = 0.94

Agregaremos estos valores a los gráficos pedidos en las últimas dos preguntas como referencia.
[19]: a_true = 7.46
b_true = 0.94

4
[20]: fig, ax = plt.subplots()
extent = (a[0], a[-1], b[0], b[-1])
im = ax.imshow(chi2, extent=extent, origin='lower', aspect='auto',
cmap='binary_r', vmax=chi2.min()+20)
plt.colorbar(im, label='$\chi^2$')
# contornos con los niveles pedidos
ax.contour(chi2, levels=chi2.min()+(2.28,5.99),
extent=extent, colors='w')
# valor obtenido a mano
ax.plot(abest, bbest, 'wo', mec='C0', mew=2, ms=10, label='Manual')
# valor obtenido con matrices
ax.plot(a_mat, b_mat, 'C4x', mew=3, ms=8, label='Matricial')
# valor real
ax.plot(a_true, b_true, 'C3+', ms=12, mew=3, label='Real')
ax.legend()
ax.set_xlabel('$a$', fontsize=15)
ax.set_ylabel('$b$', fontsize=15)

[20]: Text(0, 0.5, '$b$')

Como esperaríamos, los valores reales de a y b están dentro del contorno que contiene el 95% de la
probabilidad obtenida con el desarrollo matricial.
7) Graficar nuevamente los datos entregados en datos.txt, esta vez agregando los
modelos encontrados con ambos procedimientos, identificándolos con una leyenda.

5
[21]: def prediccion(x, a, b):
return a + b*x

[22]: fig, ax = plt.subplots()


ax.errorbar(x, y, y_err, fmt='o')
# modelos
xrng = np.linspace(0, 10, 20)
ax.plot(xrng, prediccion(xrng, a_true, b_true), 'k-', lw=3, label='Real')
ax.plot(xrng, prediccion(xrng, a_mat, b_mat), 'C1--', lw=2, label='Matricial')
ax.plot(xrng, prediccion(xrng, abest, bbest), 'C2:', lw=2, label='Manual')
ax.legend()
ax.set_xlabel('x', fontsize=15)
ax.set_ylabel('y', fontsize=15)

[22]: Text(0, 0.5, 'y')

También podría gustarte