Estoy tratando de escribir mi propio código Python para calcular t-statistics y p-values para una y dos pruebas t independientes con cola. Puedo usar la aproximación normal, pero por el momento estoy tratando de usar la distribución t. No he podido comparar los resultados de la biblioteca de estadísticas de SciPy en mis datos de prueba. Podría usar un par de ojos frescos para ver si estoy cometiendo un error tonto en alguna parte.Rastreando las suposiciones hechas por la función `ttest_ind()` de SciPy
Tenga en cuenta que esto es cross-posted from Cross-Validated porque ha estado ahí por un tiempo sin respuestas, así que pensé que no estaría de más recibir algunas opiniones de los desarrolladores de software. Estoy tratando de entender si hay un error en el algoritmo que estoy usando, que debería reproducir el resultado de SciPy. Este es un algoritmo simple, por lo que es desconcertante por qué no puedo encontrar el error.
Mi código:
import numpy as np
import scipy.stats as st
def compute_t_stat(pop1,pop2):
num1 = pop1.shape[0]; num2 = pop2.shape[0];
# The formula for t-stat when population variances differ.
t_stat = (np.mean(pop1) - np.mean(pop2))/np.sqrt(np.var(pop1)/num1 + np.var(pop2)/num2)
# ADDED: The Welch-Satterthwaite degrees of freedom.
df = ((np.var(pop1)/num1 + np.var(pop2)/num2)**(2.0))/( (np.var(pop1)/num1)**(2.0)/(num1-1) + (np.var(pop2)/num2)**(2.0)/(num2-1))
# Am I computing this wrong?
# It should just come from the CDF like this, right?
# The extra parameter is the degrees of freedom.
one_tailed_p_value = 1.0 - st.t.cdf(t_stat,df)
two_tailed_p_value = 1.0 - (st.t.cdf(np.abs(t_stat),df) - st.t.cdf(-np.abs(t_stat),df))
# Computing with SciPy's built-ins
# My results don't match theirs.
t_ind, p_ind = st.ttest_ind(pop1, pop2)
return t_stat, one_tailed_p_value, two_tailed_p_value, t_ind, p_ind
Actualización:
Después de leer un poco más en la prueba t de Welch, vi que debo utilizar la fórmula de Welch-Satterthwaite para calcular los grados de libertad. Actualicé el código anterior para reflejar esto.
Con los nuevos grados de libertad, obtengo un resultado más cercano. Mi valor de p de dos lados está desactivado en aproximadamente 0.008 desde la versión de SciPy ... pero sigue siendo un error demasiado grande, así que todavía debo estar haciendo algo incorrecto (o las funciones de distribución de SciPy son muy malas, pero es difícil de creer solo tienen una precisión de 2 decimales).
Segunda actualización:
Sin dejar de probar cosas, pensé que tal vez la versión de SciPy calcula automáticamente la aproximación normal a la distribución t cuando los grados de libertad son lo suficientemente alta (aproximadamente> 30). Así que volví a ejecutar mi código utilizando la distribución Normal en su lugar, y los resultados calculados están más alejados de SciPy que cuando uso la distribución t.
Bono pregunta :) (teoría estadística relacionada más, no dude en pasar por alto)
Además, el estadístico t es negativo. Me preguntaba qué significa esto para la prueba t unilateral. ¿Esto significa típicamente que debería estar mirando en la dirección del eje negativo para la prueba? En mis datos de prueba, la población 1 es un grupo de control que no recibió un determinado programa de capacitación laboral. La población 2 sí la recibió, y los datos medidos son diferencias salariales antes/después del tratamiento.
Así que tengo alguna razón para pensar que la media para la población 2 será mayor. Pero desde el punto de vista de la teoría estadística, no parece correcto inventar una prueba de esta manera. ¿Cómo podría haber sabido comprobar (en una prueba unilateral) en la dirección negativa sin confiar en el conocimiento subjetivo sobre los datos? ¿O es solo una de esas cosas frecuentistas que, si bien no son filosóficamente rigurosas, deben hacerse en la práctica?
Ya son funciones en scipy.stats para calcular esto: ttest_ind y ttest_rel –
favor, vuelva a leer mi pregunta. – ely
Hay dos razones. (a) Este no es el código final (que estará en C++), pero quería asegurarme de que mi algoritmo fuera correcto antes de escribir la versión .cpp. A través de Boost puedo obtener la mayoría de las funciones de conveniencia de CDF y es simple escribir mis propias calculadoras de media y varianza. Así que ilustrando que esto funciona en mis datos de prueba en Python (mucho más fácil que probarlo en C++, donde no tengo un método competitivo para comparar), me hace saber que lo estoy haciendo bien para poder seguir adelante. – ely