Estou tentando escrever meu próprio código Python para calcular estatísticas t e valores-p para um e dois testes t independentes de cauda. Eu posso usar a aproximação normal, mas no momento estou tentando usar apenas a distribuição t. Não consegui corresponder os resultados da biblioteca de estatísticas do SciPy nos meus dados de teste. Eu poderia usar um novo par de olhos para ver se estou apenas cometendo um erro estúpido em algum lugar.
Observe que isso não é tanto uma questão de codificação quanto uma "por que esse cálculo não está produzindo a estatística t correta?" Dou o código de integridade, mas não espero conselhos de software. Apenas ajude a entender por que isso não está certo.
Meu 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
Atualizar:
Depois de ler um pouco mais sobre o teste t de Welch, vi que deveria usar a fórmula Welch-Satterthwaite para calcular graus de liberdade. Eu atualizei o código acima para refletir isso.
Com os novos graus de liberdade, chego a um resultado mais próximo. Meu valor p bilateral é cerca de 0,008 da versão SciPy ... mas ainda é um erro muito grande, por isso ainda devo estar fazendo algo incorreto (ou as funções de distribuição do SciPy são muito ruins, mas é difícil de acreditar) eles são precisos apenas com 2 casas decimais).
Segunda atualização:
Enquanto continuava tentando as coisas, pensei que talvez a versão do SciPy calcule automaticamente a aproximação Normal à distribuição t quando os graus de liberdade forem altos o suficiente (aproximadamente> 30). Então, refiz meu código novamente usando a distribuição Normal, e os resultados calculados estão realmente mais distantes do SciPy's do que quando eu uso a distribuição t.
numpy.var
. A versão que vi parece indicar que a estimativa do MLE é calculada por padrão, em vez da estimativa imparcial. Para obter uma estimativa imparcial, é necessário chamá-lo com o opcional ddof=1
. ( 2 ) Para obter o limite superior -valor, utilizar a simetria do -distribuição, ou seja, e ( 3 ) para a-dois atado -valor, fazer algo semelhante: . one_tailed_p_value = st.t.cdf(-t_stat,df)
two_tailed_p_value = 2*st.t.cdf(-np.abs(t_stat),df)