SciPyのttest_ind()関数によって行われた仮定を追跡する


8

1つおよび2つのテールの独立したt検定のt統計とp値を計算するために、独自のPythonコードを記述しようとしています。通常の近似を使用できますが、現時点ではt分布のみを使用しようとしています。SciPyの統計ライブラリの結果をテストデータと照合することに失敗しました。私はどこかでばかげた間違いをしているかどうかを確認するために新鮮な目を使用することができました。

これは「なぜこの計算で正しいt統計が得られないのか」ということなので、これはコーディングの問題ではありません。完全を期すためにコードを提供しますが、ソフトウェアのアドバイスは期待していません。これが正しくない理由を理解するのに役立ちます。

私のコード:

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

更新:

ウェルチのt検定についてもう少し読んだ後、自由度を計算するためにウェルチ-サッターウェイト式を使用する必要があることがわかりました。これを反映するために上記のコードを更新しました。

新しい自由度により、より近い結果が得られます。私の両側のp値はSciPyバージョンのものから約0.008ずれています...しかし、これはまだ大きすぎるエラーなので、まだ何か間違っている必要があります(またはSciPy分布関数が非常に悪いですが、信じがたいです小数点以下2桁までしか正確ではありません)。

2回目の更新:

物事を試し続けている間に、自由度が十分に高い(およそ30より大きい)場合、SciPyのバージョンはt分布の法線近似を自動的に計算すると思いました。そこで、代わりに正規分布を使用してコードを再実行しました。計算結果は、t分布を使用する場合よりも実際にはSciPyの距離から離れています。


たぶん、SciPyはウェルチのt検定を計算します-SciPyのドキュメントでは指定されていません...
シアン

私の計算で使用している式は、ウェルチのt統計と同じです。私の知る限り、これはサンプルサイズと母集団の分散が異なることが許可されている場合に行う「標準」のことです。
e'12年

4
自由度の計算で(現在の)分子の2乗を使用する必要はありませんか?また、実質的にはコードの変更で、そこにある多くの計算のより安全な方法 -値が。現在実装されている方法は、キャンセルによる大きなエラーの影響を非常に受けやすくなっていますp
枢機卿

4
1)のドキュメントを確認してくださいnumpy.var。私が見たバージョンは、MLE推定が不偏推定ではなくデフォルトで計算されることを示しているようです。公平な見積もりを取得するには、オプションでを呼び出す必要がありますddof=1。(2)上側の値については、分布の対称性を使用します。つまり、(3)両側の値については、同様のことを行います。ptone_tailed_p_value = st.t.cdf(-t_stat,df)ptwo_tailed_p_value = 2*st.t.cdf(-np.abs(t_stat),df)
枢機卿、

2
何かの数式を手元に置くことと、安全で効率的な計算方法を知ることとの間にかなりのギャップがあるという意味で、私はそれをそれほど些細なことだとは思いません。これは、そのようなトリックを1つずつすべて自分で習得するには事実上永遠を要するため、すでに大量の知識を利用できるのは良いことの1つです。:)
枢機卿、

回答:


4

SciPy組み込み関数source()を使用することにより、関数ttest_ind()のソースコードの出力を確認できました。ソースコードに基づいて、SciPyビルトインは2つのサンプルの分散が等しいと仮定してt検定を実行しています。Welch-Satterthwaite自由度を使用していません。

重要なのは、ライブラリ関数だけを信頼すべきではない理由です。私の場合、実際には不等分散の母集団のt検定が必要です。これを実行する小さなデータセットの一部では、自由度の調整が重要になる場合があります。SciPyは等しい分散を仮定しますが、この仮定を述べていません。

いくつかのコメントで述べたように、私のコードとSciPyの差異は、サンプルサイズが30から400の場合は約0.008で、サンプルサイズが大きい場合はゆっくりとゼロになります。これは、等分散t統計の分母の余分な(1 / n1 + 1 / n2)項の影響です。精度に関しては、これは特にサンプルサイズが小さい場合に非常に重要です。自分の関数を書く必要があることは間違いなく確認できます。(おそらく他のより優れたPythonライブラリがあるかもしれませんが、これは少なくとも知られているはずです。正直言って、これがttest_ind()のSciPyドキュメントの前のどこにもないのは驚くべきことです)。


3
:正しくウェルチのt検定を指定するには、オプションのparam経由scipyのダウンロード0.11.0のように実装されて表示されますdocs.scipy.org/doc/scipy/reference/generated/...
Abhijitラオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.