Up

3 検定

 

本書の第3章に関連するPythonスクリプト例として、2項分布平均値の検定ウェルチの(Welch’s t等分散の検定相関係数の検カイ2乗検定を行うものを以下に用意した。スクリプトファイルは圧縮ファイルchap3_files.zipにまとめた。ダウンロード・展開すれば自由に利用できる。

スクリプトファイルをJupyter Notebook用にまとめたものは、圧縮ファイルchap3_prgs.zipとして用意した。ダウンロード展開して自由に利用されたい。

なお、p値についての議論があるが、これに関するウェブサイトも用意している。

ベイズ分析のPythonスクリプト例は、このウェブサイトなどに用意している。

 

 

2項分布

 

2項分布(本書(3.1.1)式)による検定のスクリプトを、リスト3.1のように書いてみた。

 

リスト3.1 2項分布による検定(s3_combi_test_code.py

 

import scipy.special as sp

 

def cum_p_comb(p, N, k):

    v = 0.0

    for i in range(k+1):

        v += sp.comb(N, i) * (p**i) * ((1-p)**(N-i))

    return v

 

p = float(input('p = '))

N = int(input('N = '))

k = int(input('k = '))

print(cum_p_comb(p, N, k))

 

リスト3.1 を実行すると、例えば以下のようになる。

 

p = 0.5

N = 5

k = 3

0.8125

 

実行すると、確率p、試行数N、成功試行数kの値の入力が求められるので、それぞれ設定していく。kの値を入力すると、計算が始まり、累積確率が算出されて表示される。

 

リスト3.1のスクリプトをPythonの関数を利用するものに書き直すと、リスト3.1のようになる。

 

リスト3.2 2項分布の関数を用いたスクリプト(s3_combi_test.py

 

import scipy.stats as ss

 

p = float(input('p = '))

N = int(input('N = '))

k = int(input('k = '))

print(ss.binom_test(k, N, p, alternative = 'less'))

 

実行は、リスト3.1の場合と同様である。

 

 

平均値の検定

 

独立なデータの平均値の差の検定に用いられるt値を本書3.2.3)式に従って求めるスクリプトをリスト3.3に示す。

 

リスト3.3 独立なデータの平均値の差のt値(s3_test_ind_code.py

 

import numpy as np

import scipy.stats as ss

 

X = [5.128, 4.0, 4.587, 4.831]

Y = [4.082, 3.571, 3.891, 3.413]

 

print('X =\n', X)

print('Y =\n', Y)

 

mean_X = np.mean(X)

mean_Y = np.mean(Y)

M = len(X)

N = len(Y)

s_2 = (np.sum((X - mean_X)**2) + np.sum((Y - mean_Y)**2)) / (M + N -2)

s_x_y_2 = (s_2/M) + (s_2/N)

 

t = (mean_X - mean_Y) / (s_x_y_2 ** 0.5)

 

print('\nt =', t)

 

df = M + N -2

print('df =', df)

p = ss.t.cdf(t, df)

print('P(X < t) =', p)

print('P(X > t) =', 1-p)

 

リスト3.3を実行すると以下の出力を得る。

 

X =

 [5.128, 4.0, 4.587, 4.831]

Y =

 [4.082, 3.571, 3.891, 3.413]

 

t = 3.168566998316026

df = 6

P(X < t) = 0.9903230788463271

P(X > t) = 0.009676921153672913

 

t値とともに、その左側の確率P(X < t)と右側の確率P(X > t)が出力されている。

 

リスト3.3のスクリプトをPythonの関数を用いたものに変更するとリスト3.4のようになる。

 

リスト3.4 独立なデータのt値をPythonの関数を用いて求めるスクリプト(s3_t_test_ind.py

 

import numpy as np

import scipy.stats as ss

 

X = [5.128, 4.0, 4.587, 4.831]

Y = [4.082, 3.571, 3.891, 3.413]

 

print('X =\n', X)

print('Y =\n', Y)

 

M = len(X)

N = len(Y)

df = M + N -2

print('df =', df)

 

Results = ss.ttest_ind(X, Y, alternative = 'less')

#print(Results)

 

#print('df =', df)

print('t =', Results[0])

print('P(X < t) =', Results[1])

print('P(X > t) =', 1 - Results[1])

 

リスト3.4を実行すると以下の出力を得る。

 

X =

 [5.128, 4.0, 4.587, 4.831]

Y =

 [4.082, 3.571, 3.891, 3.413]

df = 6

t = 3.168566998316026

P(X < t) = 0.9903230788463271

P(X > t) = 0.009676921153672913

 

 

ウェルチのt(Welch’s t

ウェルチのtを求めるプログラム例を拙著p.75の説明に基づき以下のように用意した。

 

import numpy as np

import scipy.stats as ss

 

X = [5.128, 4.0, 4.587, 4.831]

Y = [4.082, 3.571, 3.891, 3.413]

 

print('X =\n', X)

print('Y =\n', Y)

 

mean_X = np.mean(X)

mean_Y = np.mean(Y)

M = len(X)

N = len(Y)

sx_2 = np.sum((X - mean_X)**2) / (M - 1)

sy_2 = np.sum((Y - mean_Y)**2) / (N - 1)

s_x_y_2 = (sx_2/M) + (sy_2/N)

 

t = (mean_X - mean_Y) / (s_x_y_2 ** 0.5)

 

print("\nt' =", t)

 

df = (((sx_2/M) + (sy_2/N))**2) / \

       (((sx_2**2) / ((M**2) * (M-1))) + ((sy_2**2) / ((N**2) * (N-1))))

print("df' =", df)

p = ss.t.cdf(t, df)

print("P(X < t') =", p)

print("P(X > t') =", 1-p)

 

上記スクリプトを実行すると、以下の出力を得る。

 

X =

 [5.128, 4.0, 4.587, 4.831]

Y =

 [4.082, 3.571, 3.891, 3.413]

 

t' = 3.168566998316026

df' = 5.071464740943024

P(X < t') = 0.9878141600854486

P(X > t') = 0.012185839914551355

 

 

対応のあるデータの平均値の差の検定で用いるt値を、本書3.2.6)式によって求めるスクリプトを、リスト3.5に示す。

 

リスト3.5 対応のあるデータの平均値の差の検定のt値を求めるスクリプト(s3_t_test_rel_code.py

 

import numpy as np

import scipy.stats as ss

 

data = [[80, 85], [90, 88], [40, 60], [55, 70], [30, 40]]

print(data)

d = np.array(data).T[0] - np.array(data).T[1]

 

N = len(d)

d_mean = np.mean(d)

s_2 = np.sum((d - d_mean) ** 2) / (N - 1)

 

t = d_mean / ((s_2 / N) ** 0.5)

 

df = N - 1

print('\nt =', t)

print('df =', df)

p = ss.t.cdf(t, df)

print('P(X < t) =', p)

print('P(X > t) =', 1-p)

 

リスト3.5を実行すると、以下の出力が得られる。

 

X =

 [80, 90, 40, 55, 30]

Y =

 [85, 88, 60, 70, 40]

 

t = -2.5072881487467367

df = 4

P(X < t) = 0.03312441496721379

P(X > t) = 0.9668755850327863

 

リスト3.5Pythonの関数を用いたものに書き直すと、リスト3,6のようになる。

 

リスト3.6 Pythonの関数を用いた対応のあるデータのt値を求めるスクリプト(s3_t_test_rel.py

 

import numpy as np

import scipy.stats as ss

 

data = [[80, 85], [90, 88], [40, 60], [55, 70], [30, 40]]

print(data)

d = np.array(data).T[0] - np.array(data).T[1]

 

N = len(d)

df = N - 1

 

Results = ss.ttest_1samp(d, popmean = 0, alternative = 'less')

 

print('\nt =', Results[0])

print('df =', df)

print('P(X < t) =', Results[1])

print('P(X > t) =', 1-Results[1])

 

リスト3.6を実行すると、以下の出力を得る。

 

X =

 [80, 90, 40, 55, 30]

Y =

 [85, 88, 60, 70, 40]

 

t = -2.5072881487467367

df = 4

P(X < t) = 0.03312441496721379

P(X > t) = 0.9668755850327863

 

 

等分散の検定

 

等分散の検定を、本書(3.2.7)式により行うスクリプトを、リスト3.7に用意した。

 

リスト3.7 等分散の検定スクリプト(s3_F_test_EqVar.py

 

import numpy as np

import scipy.stats as ss

 

X = [5.128, 4.0, 4.587, 4.831]

Y = [4.082, 3.571, 3.891, 3.413]

X = np.array(X)

Y = np.array(Y)

 

print('X =\n', X)

print('Y =\n', Y)

 

mean_X = np.mean(X)

mean_Y = np.mean(Y)

M = len(X)

N = len(Y)

s_X_2 = np.sum((X - mean_X)**2) / (M - 1)

s_Y_2 = np.sum((Y - mean_Y)**2) / (N - 1)

 

F = s_X_2 / s_Y_2

 

print('F =', F)

 

df1 = M - 1

df2 = N - 1

print('df1 =', df1)

print('df2 =', df2)

p = ss.f.cdf(F, df1, df2)

print('P(X < F) =',p)

print('P(X > F) =', 1-p)

 

リスト3.7を実行すると、以下の出力を得る。

 

X =

 [5.128 4.    4.587 4.831]

Y =

 [4.082 3.571 3.891 3.413]

F = 2.495833374961741

df1 = 3

df2 = 3

P(X < F) = 0.7638463585081164

P(X > F) = 0.23615364149188356

 

 

相関係数の検定

 

相関係数の検定を、本書(3.2.10)によって行うスクリプトを、リスト3.8に示す。

 

リスト3.8 相関係数の検定スクリプト(s3_corr_code.py

 

import numpy as np

import scipy.stats as ss

 

data = [

        (70, 168), (68, 165), (62, 159), (56, 156), (70, 170),

        (64, 162), (59, 162), (70, 169), (68, 168), (69, 170),

        (67, 168), (63, 166), (58, 163), (74, 170), (65, 168),

        (60, 160), (65, 165), (72, 175), (61, 164), (77, 174),

        (68, 164), (64, 161), (70, 166), (47, 147), (66, 165),

        (68, 170), (73, 174), (74, 172), (63, 164), (83, 182),

        (58, 159), (64, 166), (67, 167), (75, 174), (67, 163),

        (68, 166), (68, 167), (66, 165), (63, 165), (55, 154),

        (61, 163), (60, 160), (62, 164), (62, 160), (59, 160),

        (51, 155), (59, 163), (68, 170), (56, 157), (79, 180)]

 

data = np.array(data)

print(data)

 

mx = np.mean(data.T[0])

my = np.mean(data.T[1])

 

SXY  = np.sum((data.T[0] - mx) * (data.T[1] - my))

SX2 = np.sum((data.T[0] - mx)**2)

SY2 = np.sum((data.T[1] - my)**2)

r = SXY / ((SX2 * SY2) ** 0.5)

 

print('\nr =', r)

 

N = len(data)

print('N =', N)

t = r * ((N - 2)**0.5) / ((1 - r**2)**0.5)

print('t =', t)

 

df = N - 2

print('df =', df)

p = ss.t.cdf(t, df)

print('P(X < t) =', p)

print('P(X > t) =', 1-p)

 

リスト3.8を実行すると、以下の出力を得る。

 

r = 0.9428052005583538

N = 50

t = 19.595199469782504

df = 48

P(X < t) = 1.0

P(X > t) = 0.0

 

 

カイ2乗検定

 

本書の表3.3.3のデータに対して式(3.3.1)によるカイ2乗検定を行うスクリプトを、リスト3.9のように作成した。

 

リスト3.9 適合度の検定スクリプト(s3_chi2fit_code.py

 

import numpy as np

import scipy.stats as ss

 

pj = [1/2, 1/2]

Oj = [16, 4]

pj = np.array(pj)

Oj = np.array(Oj)

c = len(Oj)

Ej = np.empty(c)

print('pj =', pj)

print('Oj =', Oj)

 

N = np.sum(Oj)

print('N =', N)

 

for j in range(c):

    Ej[j] = N * pj[j]

print('Ej =', Ej)

 

chi2 = 0

for j in range(c):

    chi2 += ((Oj[j] - Ej[j])**2) / Ej[j]

print('ch2 =', chi2)

 

df = c - 1

print('df =', df)

p_chi2 = 1 - ss.chi2.cdf(chi2, df)

print('p =', p_chi2)

 

リスト3.9を実行すると、以下の出力を得る。

 

pj = [0.5 0.5]

Oj = [16  4]

N = 20

Ej = [10. 10.]

ch2 = 7.2

df = 1

p = 0.007290358091535665

 

リスト3.9のスクリプトをPythonの関数を用いたものに書き直すと、リスト3.10のようになる。

 

リスト3.10 Pythonの関数を用いた適合度検定スクリプト(s3_chi2fit.py

 

import numpy as np

import scipy.stats as ss

 

pj = [1/2, 1/2]

Oj = [16, 4]

pj = np.array(pj)

Oj = np.array(Oj)

c = len(Oj)

Ej = np.empty(c)

print('pj =', pj)

print('Oj =', Oj)

 

N = np.sum(Oj)

print('N =', N)

 

for j in range(c):

    Ej[j] = N * pj[j]

print('Ej =', Ej)

 

Results = ss.chisquare(Oj, Ej)

print('chi2 =', Results[0])

print('p =', Results[1])

 

リスト3.10を実行すると、以下の出力を得る。

 

pj = [0.5 0.5]

Oj = [16  4]

N = 20

Ej = [10. 10.]

chi2 = 7.2

p = 0.0072903580915356595

 

 

本書の表3.3.5のデータを、式(3.3.4)によって分布の違いを検定するスクリプトをリスト3.11のように作成した。

 

リスト3.11 分布の違いの検定スクリプト(s3_chi2_between_rows_code.py

 

import numpy as np

import scipy.stats as ss

 

Oij = [[23, 27],

       [38, 12]]

Oij = np.array(Oij)

print('Oij =\n', Oij)

 

r = len(Oij)

c = len(Oij[0])

print('r =', r)

print('c =', c)

 

ni = np.sum(Oij, axis=1)

print('ni =', ni)

 

Cj =np.sum(Oij, axis=0)

print('Cj =', Cj)

 

N = np.sum(Oij)

print('N =', N)

 

Eij = np.empty((r, c))

for i in range(r):

    for j in range(c):

        Eij[i][j] = ni[i] * Cj[j] / N

 

chi2 = 0.0

for i in range(r):

    for j in range(c):

        chi2 += ((Oij[i][j] - Eij[i][j])**2) / Eij[i][j]

 

print('\nchi2 =', chi2)

       

df = (r - 1) * (c - 1)

p_value = 1.0 - ss.chi2.cdf(chi2, df)

print('p =', p_value)

print('df =', df)

 

リスト3.11を実行すると、以下の出力を得る。

 

Oij =

 [[23 27]

 [38 12]]

r = 2

c = 2

ni = [50 50]

Cj = [61 39]

N = 100

 

chi2 = 9.457755359394703

p = 0.002102582110668938

df = 1

 

 

本書の表3.3.6のデータを、式(3.3.7)によって独立性の検定を行うスクリプトをリスト3.12のように用意した。

 

リスト3.12 独立性の検定スクリプト(s3_chi2Ind_code.py

 

import numpy as np

import scipy.stats as ss

 

Oij = [[29, 24],

       [26, 21]]

Oij = np.array(Oij)

print('Oij =\n', Oij)

 

r = len(Oij)

c = len(Oij[0])

print('r =', r)

print('c =', c)

 

Ri = np.sum(Oij, axis=1)

print('ni =', Ri)

 

Cj =np.sum(Oij, axis=0)

print('Cj =', Cj)

 

N = np.sum(Oij)

print('N =', N)

 

Eij = np.empty((r, c))

for i in range(r):

    for j in range(c):

        Eij[i][j] = Ri[i] * Cj[j] / N

print('Eij =\n', Eij)

 

chi2 = 0.0

for i in range(r):

    for j in range(c):

        chi2 += ((Oij[i][j] - Eij[i][j])**2) / Eij[i][j]

 

print('\nchi2 =', chi2)

       

df = (r - 1) * (c - 1)

print('df =', df)

p_value = 1.0 - ss.chi2.cdf(chi2, df)

print('p =', p_value)

 

リスト3.12を実行すると以下の出力を得る。

 

Oij =

 [[29 24]

 [26 21]]

r = 2

c = 2

ni = [53 47]

Cj = [55 45]

N = 100

Eij =

 [[29.15 23.85]

 [25.85 21.15]]

 

chi2 = 0.0036495018429983615

df = 1

p = 0.951828212747989

 

リスト3.12Pythonの関数を用いたものに書き直すとリスト3.13のようになる。

 

リスト3.13 Pythonの関数を用いた独立性検定スクリプト(s3_chi2Ind.py

 

import numpy as np

import scipy.stats as ss

 

Oij = [[29, 24],

       [26, 21]]

Oij = np.array(Oij)

print('Oij =\n', Oij)

 

r = len(Oij)

c = len(Oij[0])

print('r =', r)

print('c =', c)

 

Results = ss.chi2_contingency(Oij, correction = False)

 

print('Eij =\n', Results[3])

print('\nchi2 =', Results[0])

print('df =', Results[2])

print('p =', Results[1])

 

リスト3.13を実行すると以下の出力を得る。

 

Oij =

 [[29 24]

 [26 21]]

r = 2

c = 2

Eij =

 [[29.15 23.85]

 [25.85 21.15]]

 

chi2 = 0.0036495018429983615

df = 1

p = 0.951828212747989

 

 

Up