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 opcionalddof=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)
Respostas:
Usando a função interna SciPy source (), pude ver uma impressão do código fonte da função ttest_ind (). Com base no código-fonte, o SciPy interno está executando o teste t, assumindo que as variações das duas amostras são iguais. Não está usando os graus de liberdade Welch-Satterthwaite.
Eu só quero ressaltar que, crucialmente, é por isso que você não deve apenas confiar nas funções da biblioteca. No meu caso, eu realmente preciso do teste t para populações de variações desiguais, e os graus de ajuste da liberdade podem ser importantes para alguns dos conjuntos de dados menores nos quais executarei isso. O SciPy assume variações iguais, mas não afirma essa suposição.
Como mencionei em alguns comentários, a discrepância entre meu código e o SciPy's é de cerca de 0,008 para tamanhos de amostra entre 30 e 400 e depois lentamente passa a zero para tamanhos de amostra maiores. Este é um efeito do termo extra (1 / n1 + 1 / n2) no denominador estatístico de variâncias iguais. Em termos de precisão, isso é muito importante, especialmente para amostras pequenas. Definitivamente, confirma-me que preciso escrever minha própria função. (Possivelmente, existem outras bibliotecas Python melhores, mas isso pelo menos deve ser conhecido. Francamente, é surpreendente que isso não esteja em nenhum lugar na frente e no centro da documentação do SciPy para ttest_ind ()).
fonte