Alumno: Mauro Silberberg

Libreta: 408/10

Guia 9, Ejercicio 14

In [1]:
import numpy as np
import scipy.stats as st
import matplotlib.pyplot as plt
%matplotlib inline

plt.rcParams['figure.figsize'] = (10, 5)
plt.rcParams['lines.linewidth'] = 3
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['axes.labelsize'] = 20
plt.rcParams['legend.fontsize'] = 20
plt.rcParams['legend.numpoints'] = 1
In [2]:
def hist(data, bins=10, normed=False, plot=True, ax=None, **kwargs):
    '''Grafica histogramas con barras de error'''
    y, bins = np.histogram(data, bins=bins) #Divido los datos en bins
    binwidth = np.diff(bins)
    
    yerr = hist_err(y, binwidth)
    
    if normed:
        norm = np.sum(y) * binwidth
        y = y / norm
        yerr = yerr / norm
    
    if plot:
        if ax is None:
            f, ax = plt.subplots(1,1)
        ax.bar(bins[:-1], y, width=binwidth, yerr=yerr, **kwargs)
    return y, yerr, bins

def hist_err(y, binwidth):
    '''Calcula el error (binomial) para un histograma'''
    N = np.sum(y)
    p = y * binwidth / np.sum(y * binwidth)
    return np.sqrt(p * (1 - p) * N)

errdict = dict(ecolor='r', elinewidth=3, capsize=5, capthick=3, alpha=0.75)
formato = dict(color='r', alpha=0.5, error_kw=errdict)

Los siguientes son los datos del ejercicio 7 de la guia 5, los cuales se ajusta por cuadrados minimos a una recta. Se utiliza la función polyfit sin considerar el error en la variable y ya que es igual para todos y por lo tanto no cambia el resultado.

In [3]:
X = [2.00, 2.10, 2.20, 2.30, 2.40, 2.50, 2.60, 2.70, 2.80, 2.90, 3.00] #Datos en x
Y = [2.78, 3.29, 3.29, 3.33, 3.23, 3.69, 3.46, 3.87, 3.62, 3.40, 3.99] #Datos en y
Sy = 0.3 # Error en y

def recta(x, p):
    x = np.asarray(x)
    return p[1] + p[0] * x

p = np.polyfit(X, Y, 1) # Ajusto por una función lineal
print('Pendiente: {:.3f}, Ordenada: {:.3f}'.format(p[0], p[1]))
Pendiente: 0.799, Ordenada: 1.452

Se considera esta recta obtenida como la teórica y se generan a partir de esta un nuevo conjunto $\{\hat{y}_i\}$ de $11$ datos, donde cada $\hat{y}_i$ tiene distribución normal $N(y_i = f(x_i), \, \sigma)$.

A partir este conjunto se realizan 2 calculos de $\chi^2$:

El primero es de los nuevos puntos respecto de la recta original, es decir:

$$ \chi^2 = \sum_{i=1}^{11} \left(\frac{\hat{y}_i - y_i}{\sigma}\right)^2 = \sum_{i=1}^{11} \chi^2_{1} = \chi^2_{11} $$

Este estadístico tiene una distribución $\chi^2$ de $11$ grados de libertad.

Por otro lado, a los nuevos $\hat{y}_i$ se les ajusta una nueva recta de la forma $y = ax + b$ y se obtienen unos nuevos estimadores $\hat{a}$ y $\hat{b}$. A partir de estos se calcula entonces:

$$ \chi^2 = \sum_{i=1}^{11} \left(\frac{\hat{y}_i - (\hat{a}x_i + \hat{b})}{\sigma}\right)^2 = \chi^2_{9} $$

Se puede demostrar que al estar estimando $p = 2$ parametros con $n = 11$ datos, este ultimo estadístico es una variable $\chi^2$ de $\nu = n-p = 9$ grados de libertad. Las hipotesis para que esto suceda es que los errores en las variables $y_i$ sean gaussianos, y la función a estimar sea lineal en los parametros.

Se repite este proceso $1000$ veces y se generan 2 histogramas de los estadisticos $\chi^2$. Para el primero se superpone con su distribución correspondiente, mientras que el segundo histograma se muestra con las distribuciones $\chi^2$ de $9$ y $11$ grados de libertad. Es decir, la correcta y la cual no se tuvo en cuenta que se ajustaron parametros, respectivamente.

A simple vista, para el primer caso, la $\chi^2_{11}$ es representativa de los datos, mientras que en el segundo caso no lo es. Se realiza un test de Kolmogorov cuya hipotesis nula es que los datos provengan de una distribución $\chi^2_\nu$, y se observa que los p-values para los $\nu$ incorrectos son insignificantes.

In [4]:
def chi2(f, p, x, y, sy):
    return np.sum(((y-f(x, p))/sy)**2)

chi2_teo = []
chi2_fit = []
for i in range(1000):
    Yr = st.norm(loc=recta(X, p), scale=Sy).rvs(len(X)) # Genero datos con distribución normal
    pr = np.polyfit(X, Yr, 1) # Ajusto la recta
    
    chi2_teo.append(chi2(recta, p, X, Yr, Sy))
    chi2_fit.append(chi2(recta, pr, X, Yr, Sy))    
In [5]:
x = np.linspace(0, 35, 100)

hist(chi2_teo, normed=True, bins=20, **formato)
plt.plot(x, st.chi2.pdf(x, len(X)), label='$\chi^2_{(11)}$')
plt.xlabel('$\chi^2$')
plt.legend()

print('Kolmogorov-Smirnov test\n')
print('{} | {}'.format('ν'.rjust(2), 'p-value'))
print('------------')
for i in range(9, 14):
    p = st.kstest(chi2_teo, 'chi2', [i])[1]
    print('{} |  {:.3g}'.format(str(i).rjust(2), p))
Kolmogorov-Smirnov test

 ν | p-value
------------
 9 |  0
10 |  2.29e-08
11 |  0.503
12 |  4.05e-11
13 |  0
In [6]:
hist(chi2_fit, normed=True, bins=20, **formato)
plt.plot(x, st.chi2.pdf(x, len(X)), label='$\chi^2_{(11)}$')
plt.plot(x, st.chi2.pdf(x, len(X)-2), label='$\chi^2_{(9)}$')
plt.xlabel('$\chi^2$')
plt.legend()

print('Kolmogorov-Smirnov test\n')
print('{} | {}'.format('ν'.rjust(2), 'p-value'))
print('------------')
for i in range(7, 12):
    p = st.kstest(chi2_fit, 'chi2', [i])[1]
    print('{} |  {:.3g}'.format(str(i).rjust(2), p))
Kolmogorov-Smirnov test

 ν | p-value
------------
 7 |  0
 8 |  6.84e-13
 9 |  0.671
10 |  1.43e-10
11 |  0