Aufspüren der Annahmen, die von SciPys Funktion ttest_ind () getroffen wurden

8

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.

ely
quelle
Vielleicht berechnet SciPy den T-Test von Welch - SciPys Dokumentation spezifiziert nicht ...
Cyan
Die Formel, die ich in meiner Berechnung verwende, entspricht der t-Statistik von Welch. Meines Wissens ist dies der "Standard", wenn die Stichprobengrößen und Populationsabweichungen unterschiedlich sein dürfen, richtig?
ely
4
Müssen Sie bei der Berechnung der Freiheitsgrade nicht das Quadrat des (aktuellen) Zählers verwenden? Da praktisch keine Codeänderungen vorgenommen wurden, gibt es auch viel sicherere Methoden zur Berechnung der Werte. Die Art und Weise, wie es derzeit implementiert wird, ist aufgrund von Stornierungen äußerst anfällig für massive Fehler . p
Kardinal
4
( 1 ) Überprüfen Sie die Dokumentation von 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 werden ddof=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 pptone_tailed_p_value = st.t.cdf(-t_stat,df)ptwo_tailed_p_value = 2*st.t.cdf(-np.abs(t_stat),df)
Kardinal
2
Ich halte es nicht für so trivial, in dem Sinne, dass es oft eine beträchtliche Lücke zwischen der mathematischen Formel für etwas zur Hand und der Kenntnis einer sicheren und effizienten Methode zur Berechnung gibt. Es ist eines dieser Dinge, bei denen es schön ist, bereits über eine große Menge an Wissen zu verfügen, da es eine virtuelle Ewigkeit dauern würde, solche Tricks einzeln nacheinander zu lernen. :)
Kardinal

Antworten:

4

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.)

ely
quelle
3
Es scheint, dass dies ab Scipy 0.11.0 über einen optionalen Parameter zur Angabe des Welch-T-Tests ordnungsgemäß implementiert ist: docs.scipy.org/doc/scipy/reference/generated/…
Abhijit Rao