Ich versuche, meinen eigenen Python-Code zu schreiben, um t-Statistiken und p-Werte für einen und zwei unabhängige t-Tests zu berechnen. Ich kann die normale Näherung verwenden, aber im Moment versuche ich nur die t-Verteilung zu verwenden. Es ist mir nicht gelungen, die Ergebnisse der SciPy-Statistikbibliothek mit meinen Testdaten abzugleichen. Ich könnte ein neues Paar Augen gebrauchen, um zu sehen, ob ich irgendwo einen dummen Fehler mache.
Beachten Sie, dass dies weniger eine Codierungsfrage ist als vielmehr eine Frage: "Warum liefert diese Berechnung nicht den richtigen t-stat?" Ich gebe den Code der Vollständigkeit halber an, erwarte aber keine Software-Beratung. Helfen Sie einfach zu verstehen, warum dies nicht richtig ist.
Mein Code:
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
Aktualisieren:
Nachdem ich etwas mehr über den T-Test des Welch gelesen hatte, sah ich, dass ich die Welch-Satterthwaite-Formel verwenden sollte, um Freiheitsgrade zu berechnen. Ich habe den obigen Code aktualisiert, um dies widerzuspiegeln.
Mit den neuen Freiheitsgraden bekomme ich ein näheres Ergebnis. Mein zweiseitiger p-Wert ist gegenüber der SciPy-Version um etwa 0,008 niedriger ... aber dies ist immer noch ein viel zu großer Fehler, sodass ich immer noch etwas falsch machen muss (oder die SciPy-Verteilungsfunktionen sind sehr schlecht, aber es ist schwer zu glauben Sie sind nur auf 2 Dezimalstellen genau.
Zweites Update:
Während ich weiter versuchte, dachte ich, dass SciPys Version möglicherweise automatisch die normale Annäherung an die t-Verteilung berechnet, wenn die Freiheitsgrade hoch genug sind (ungefähr> 30). Also habe ich meinen Code stattdessen mit der Normalverteilung erneut ausgeführt, und die berechneten Ergebnisse sind tatsächlich weiter von SciPys entfernt als bei Verwendung der T-Verteilung.
numpy.var
. Die Version, die ich gesehen habe, scheint darauf hinzudeuten, dass die MLE-Schätzung standardmäßig anstelle der unvoreingenommenen Schätzung berechnet wird. Um die unvoreingenommene Schätzung zu erhalten, muss sie mit der Option aufgerufen werdenddof=1
. ( 2 ) Verwenden Sie für den oberen Schwanz- Wert die Symmetrie der Verteilung, dh, und ( 3 ) für den zweiseitigen Wert etwas Ähnliches : . t pone_tailed_p_value = st.t.cdf(-t_stat,df)
two_tailed_p_value = 2*st.t.cdf(-np.abs(t_stat),df)
Antworten:
Mit der in SciPy integrierten Funktion source () konnte ich einen Ausdruck des Quellcodes für die Funktion ttest_ind () sehen. Basierend auf dem Quellcode führt der integrierte SciPy den t-Test unter der Annahme durch, dass die Varianzen der beiden Stichproben gleich sind. Es werden nicht die Welch-Satterthwaite-Freiheitsgrade verwendet.
Ich möchte nur darauf hinweisen, dass Sie aus diesem Grund nicht nur Bibliotheksfunktionen vertrauen sollten. In meinem Fall benötige ich tatsächlich den T-Test für Populationen mit ungleichen Varianzen, und die Anpassung der Freiheitsgrade kann für einige der kleineren Datensätze von Bedeutung sein, auf denen ich dies ausführen werde. SciPy geht von gleichen Varianzen aus, gibt diese Annahme jedoch nicht an.
Wie ich in einigen Kommentaren erwähnt habe, beträgt die Diskrepanz zwischen meinem Code und SciPy's bei Stichprobengrößen zwischen 30 und 400 etwa 0,008 und geht bei größeren Stichprobengrößen langsam auf Null. Dies ist ein Effekt des zusätzlichen Terms (1 / n1 + 1 / n2) im t-statistischen Nenner mit gleichen Varianzen. In Bezug auf die Genauigkeit ist dies ziemlich wichtig, insbesondere für kleine Stichprobengrößen. Es bestätigt mir definitiv, dass ich meine eigene Funktion schreiben muss. (Möglicherweise gibt es andere, bessere Python-Bibliotheken, aber dies sollte zumindest bekannt sein. Ehrlich gesagt ist es überraschend, dass dies in der SciPy-Dokumentation für ttest_ind () nicht im Vordergrund steht.)
quelle