「統計解析のはなし―データに語らせるテクニック」1~4章
大村平「統計解析のはなし―データに語らせるテクニック」日科技連 の読後行間補充メモ
同書籍は、印刷数表と手計算による統計解析を紹介した良書。
本稿では、同書籍の設例について、プログラムによる演算処理をした場合の例を示す。
コードと出力例は、Python[Google Colaboratory]
1章 前口上
p3 偏差値
平均値、標準偏差、A~F氏の素点 → A~F氏の偏差値 の計算例(付録1[p289])
import pandas as pd def devi_score(ave, std, raw): # 偏差値の関数 return 50 + 10*(raw-ave)/std ave = 55 # 平均 std = 12 # 標準偏差 raw_list = [31,43,55,67,73,79] # 素点 devi_list = [] for raw in raw_list: ds = devi_score(ave, std, raw) devi_list.append(ds) DF = pd.DataFrame([raw_list,devi_list], index=['素点','偏差値'], columns = ['A','B','C','D','E','F']) DF
A B C D E F 素点 31.0 43.0 55.0 67.0 73.0 79.0 偏差値 30.0 40.0 50.0 60.0 65.0 70.0
2章 素人探偵ものがたり(推定のはなし その1)
p23 平均値20万円、標準偏差10万円の正規分布
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt mean = 20 # 平均 sigma = 10 # 標準偏差 X_list = np.linspace(0, 59, 60) #0から59まで60個のリスト Y1 = norm.pdf(X_list,mean,sigma) # 確率密度関数のデータ Y2 = np.linspace(0,0,60) # 0から0まで60個のリスト(y=0 のデータ) # グラフの描画 plt.plot(X_list, Y1) # 正規分布 plt.plot(X_list, Y2, color = 'black') # x軸 plt.vlines(0,0,0.05, color = 'black') # y軸 plt.vlines(20,0,0.05) # 平均の縦軸 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=10),fc= 'lightgrey') plt.fill_between(X_list, Y1, Y2, where=(X_list>=30),fc= 'white') plt.title(f'Normal Distribution, mean={mean}, sigma={sigma}') plt.show()
p25 平均値の区間推定
- 1個のサンプル値\(x_1\)
- 母集団の標準偏差\(\sigma\)
- 信頼区間内に母平均を含む割合\(r\)
- \(x_1,\sigma,r\) → 母平均\(\mu\)を区間推定
import pandas as pd from scipy.stats import norm sample_score = float(input('サンプル値',)) sigma = float(input('母集団の標準偏差',)) conf_intervals = [68.3, 90, 95] DF = pd.DataFrame() for conf_int_element in conf_intervals: accum_probability = 1-(50-conf_int_element/2)/100 upper = round(sample_score + norm.ppf(accum_probability)*sigma,1) lower = round(sample_score - norm.ppf(accum_probability)*sigma,1) seed = pd.DataFrame([round(conf_int_element,1),lower,upper]) DF = pd.concat([DF,seed], axis=1) DF.columns = ['ex1','ex2','ex3'] DF.index = ['信頼区間','下限','上限'] DF.T
サンプル値20 母集団の標準偏差10 信頼区間 下限 上限 ex1 68.3 10.0 30.0 ex2 90.0 3.6 36.4 ex3 95.0 0.4 39.6
p26~29 標本が2つになれば(正規分布の加法性)
import numpy as np import math import pandas as pd np.random.seed(0) # 乱数 ave = 60 # 平均 std = 10 # 標準偏差 num = 200000 # サンプル数 scores1 = pd.Series(np.around(np.random.normal(ave, std, num))) # 集団1 scores2 = pd.Series(np.around(np.random.normal(ave, std, num))) # 集団2 # 新たな集団の形成 scores3s = [] # 和の集団 scores4s = [] # 平均の集団 i = 0 while i < num: s1 = float(scores1.sample(replace=True)) # 集団1よりランダム抽出 s2 = float(scores2.sample(replace=True)) # 集団2よりランダム抽出 scores3s.append(s1+s2) # 抽出した両要素の和 scores4s.append((s1+s2)/2) # 抽出した両要素の平均 i += 1 scores3 = pd.Series(scores3s) # 和の集団リスト scores4 = pd.Series(scores4s) # 平均の集団リスト # DF化 DF = pd.DataFrame([scores1, scores2, scores3, scores4]).T DF.columns = ['集団1','集団2','和の集団','平均の集団'] Means = pd.DataFrame([DF.mean()],index=['平均値']) # 各集団の平均 Stds = pd.DataFrame([DF.std()],index=['標準偏差']) # 各集団の標準偏差 DFL = pd.concat([DF, Means, Stds]) # DFの結合 # 結果表示 print(f'(平均値)\n設定値 {ave}\n2倍値 {ave*2}\n') print(f'(標準偏差)\n設定値 {std}\n√2倍 {round(std*math.sqrt(2),2)}\n1/√2倍 {round(std/math.sqrt(2),2)}\n') pd.options.display.precision = 2 # DF表示桁数 DFL
(平均値) 設定値 60 2倍値 120 (標準偏差) 設定値 10 √2倍 14.14 1/√2倍 7.07
p29 標本が2つになれば(正規分布の加法性)グラフ
# コードは上記の続き from matplotlib import pyplot as plt bins = np.linspace(0, 200, 101) # 0~200を101等分したリスト class_value = (bins[:-1] + bins[1:]) / 2 # 階級値 def graph(score, name): # グラフ描画用 freq = score.value_counts(bins=bins, sort=False) # 度数分布表 dist = pd.DataFrame({"階級値": class_value ,"度数": freq}) plt.bar(dist['階級値'],dist['度数'], width=0.5, label = name) graph(scores1, 'Population_1') # 母集団1のグラフ graph(scores3, 'Population_3') # 母集団3のグラフ plt.ylim(0, 25000) plt.xlabel('Score') plt.ylabel('Degree') plt.legend() plt.show()
p30 標本2つからの母集団の平均値の区間推定
- 2個のサンプル値からの標本平均\(\bar{x}\)
- 母集団の標準偏差\(\sigma\)
- 信頼区間内に母平均を含む割合\(r\)
- \(\bar{x},\sigma,r\) → 母平均\(\mu\)を区間推定
import numpy as np from scipy.stats import norm import pandas as pd sample_score1 = float(input('サンプル値1=',)) sample_score2 = float(input('サンプル値2=',)) sample_average = np.average([sample_score1,sample_score2]) sample_number =2 #2個のサンプル m_sigma = float(input('母集団の標準偏差=',)) sigma = m_sigma/np.sqrt(sample_number) conf_intervals = [68.3, 90, 95] DF = pd.DataFrame() for conf_int_element in conf_intervals: accum_probability = 1-(50-conf_int_element/2)/100 upper = round(sample_average + norm.ppf(accum_probability)*sigma,1) lower = round(sample_average - norm.ppf(accum_probability)*sigma,1) seed = pd.DataFrame([round(conf_int_element,1),lower,upper]) DF = pd.concat([DF,seed], axis=1) DF.columns = ['ex1','ex2','ex3'] DF.index = ['信頼区間','下限','上限'] Dataset = DF.T Dataset
サンプル値1=10 サンプル値2=30 母集団の標準偏差=10 信頼区間 下限 上限 ex1 68.3 12.9 27.1 ex2 90.0 8.4 31.6 ex3 95.0 6.1 33.9
p42 標準正規分布
import numpy as np from scipy.stats import norm import matplotlib.pyplot as plt mean = 0 # 平均 sigma = 1 # 標準偏差 X_list = np.linspace(-3, 2.9, 60) #0から59まで60個のリスト Y1 = norm.pdf(X_list,mean,sigma) # 確率密度関数のデータ Y2 = np.linspace(0,0,60) # 0から0まで60個のリスト(y=0 のデータ) # グラフの描画 plt.plot(X_list, Y1) # 正規分布 plt.plot(X_list, Y2, color = 'black') # x軸 plt.vlines(0,0,0.5, color = 'black') # y軸 plt.title('Standard Normal Distribution') # 表題 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=-sigma),fc= 'lightgrey') plt.fill_between(X_list, Y1, Y2, where=(X_list>=sigma),fc= 'white') plt.show()
p45 t分布
import numpy as np import matplotlib.pyplot as plt from scipy import stats X_list = np.linspace(-3, 3, 100) #-3から3で100個のリスト f_inf = float('inf') # 無限大 for dof in [1,5,f_inf]: # 自由度のリスト Y_list = stats.t.pdf(X_list,dof) # t分布の確率密度関数のリスト plt.plot(X_list, Y_list, label=f"Φ={dof}") # グラフを描画 plt.hlines(0,-3,3, color = 'black') # x軸 plt.vlines(0,0,0.5, color = 'black') # y軸 plt.title('T Distribution') # 表題 plt.legend() # 凡例 plt.show()
p46 両裾の面積(確率)→tの値
import numpy as np import matplotlib.pyplot as plt from scipy import stats dof = 3 # 自由度 prob = 0.1 # 両裾の面積(確率) t_value = stats.t.ppf(prob/2, dof) # 片側確率のt値 X_list = np.linspace(-3, 3, 100) #-3から3で100個のリスト Y1 = stats.t.pdf(X_list,dof) # t分布の確率密度関数のリスト Y2 = np.linspace(0,0,100) # 0から0まで100個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list >= -t_value),fc= 'lightgrey') plt.fill_between(X_list, Y1, Y2, where=(X_list <= t_value),fc= 'lightgrey') plt.hlines(0,-3,3, color = 'black') # x軸 plt.vlines(0,0,0.4, color = 'black') # y軸 plt.title(f'TD, Both_prob={prob*100}% → t={-round(t_value,4)}') # 表題 plt.legend() # 凡例 plt.show()
p46 両裾の面積(確率)→tの値の一覧表
import numpy as np from scipy import stats import pandas as pd f_inf = float('inf') # 無限大 horizon = [0.1,0.05,0.01] # 表の横軸(面積p) vertical = [1,2,3,f_inf] # 表の縦軸(自由度Φ) t_list = [] for dof in vertical: tvalues = [] for prob in horizon: t_value = round(-stats.t.ppf(prob/2, dof),3) # 片側確率のt値 tvalues.append(t_value) # 各行を形成 t_list.append(tvalues) # 各行を連結 # 階層付きDF化 mult_index = pd.MultiIndex.from_product([["Degrees of Freedom"], vertical]) #縦軸の階層化 mult_column = pd.MultiIndex.from_product([["Probability"], horizon])# 横軸の階層化 DF = pd.DataFrame(t_list, index =mult_index, columns= mult_column) DF
3章 名探偵ものがたり(推定のはなし その2)
p59 χ二乗分布(自由度1)
import numpy as np import matplotlib.pyplot as plt from scipy import stats dof = 1 # 自由度 prob = 0.1 # 両裾の面積(確率) x_length = 8 plot_n =120 X_list = np.linspace(0, x_length, plot_n) #0から8で120個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで120個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 plt.xlim(0, ) # 描画範囲を正の数に限定 plt.ylim(0, ) plt.title(r'$\chi^2$' f'distribution') # 表題 plt.legend() # 凡例 plt.show()
p59 χ二乗分布(自由度1)の上側5%部分
# import 文は上記設例 dof = 1 # 自由度 prob = 0.1 # 両裾の面積(確率) chi2_lower = stats.chi2.ppf(prob/2, dof) # 下側確率のχ二乗値 chi2_upper = stats.chi2.ppf(1-prob/2, dof) # 上側確率のχ二乗値 x_length = 6 plot_n =100 X_list = np.linspace(0, x_length, plot_n) #0から6で100個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで100個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 plt.ylim(0, 0.5) # 描画範囲を限定 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=chi2_upper),fc= 'lightgrey') plt.fill_between(X_list, Y1, Y2, where=(X_list<=chi2_lower),fc= 'lightgrey') # too small to display plt.xlim(0, ) # 描画範囲を正の数に限定 plt.ylim(0, ) plt.title(r'$\chi^2$' f', Both_P={prob*100} % →' r'$\chi^2 upper$' f'={round(chi2_upper,3)}') # 表題 plt.legend() # 凡例 plt.show()
p59 χ二乗分布(自由度1)の下側5%部分
# dof, prob, chi2_lower, chi2_upper は上記設例数値を使用 x_length = 0.05 plot_n =1000 X_list = np.linspace(0, x_length, plot_n) #0から0.05で1000個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで1000個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 plt.ylim(0, 20) # 描画範囲を限定 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=chi2_upper),fc= 'lightgrey') # outside the drawing area plt.fill_between(X_list, Y1, Y2, where=(X_list<=chi2_lower),fc= 'lightgrey') plt.xlim(0, ) # 描画範囲を正の数に限定 plt.ylim(0, ) plt.title(r'$\chi^2$' f', Both_P={prob*100} % →' r'$\chi^2 lower$' f'={round(chi2_lower,4)}') # 表題 plt.legend() # 凡例 plt.show()
p62 χ二乗分布(自由度3)の上側・下側5%部分
# import 文は上記設例 dof = 3 # 自由度 prob = 0.1 # 両裾の面積(確率) chi2_lower = stats.chi2.ppf(prob/2, dof) # 下側確率のχ二乗値 chi2_upper = stats.chi2.ppf(1-prob/2, dof) # 上側確率のχ二乗値 x_length = 10 plot_n =100 X_list = np.linspace(0, x_length, plot_n) #0から10で100個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで100個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 plt.ylim(0, max(Y1)*1.1) # 描画範囲を限定 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=chi2_upper),fc= 'grey') plt.fill_between(X_list, Y1, Y2, where=(X_list<=chi2_lower),fc= 'grey') plt.xlim(0, ) # 描画範囲を正の数に限定 plt.ylim(0, ) plt.title(f'BP={prob*100} % →' r'$\chi^2$' f'=low_{round(chi2_lower,3)}, up_{round(chi2_upper,3)}') # 表題 plt.xlabel(r'$\chi^2$') plt.legend() # 凡例 plt.show()
p65 χ二乗分布(自由度1~6)
import numpy as np import matplotlib.pyplot as plt from scipy import stats x_length = 12 plot_n =120 for dof in [1,2,3,4,5,6]: X_list = np.linspace(0, x_length, plot_n) #0から12で120個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで120個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 plt.xlim(0, ) # 描画範囲を正の数に限定 plt.ylim(0, ) plt.title(r'$\chi^2$' f'distribution') # 表題 plt.legend() # 凡例 plt.show()
p65 χ二乗値の一覧表(自由度1~6)
import numpy as np from scipy import stats import pandas as pd horizon = [0.95,0.05,0.025] # 表の横軸(面積p)上側確率 vertical = [1,2,3,4,5,6] # 表の縦軸(自由度Φ) chi_list = [] for dof in vertical: chivalues = [] for prob in horizon: chi_value = round(stats.chi2.ppf(1-prob, dof),3) # 上側確率のχ二乗値 chivalues.append(chi_value) # 各行を形成 chi_list.append(chivalues) # 各行を連結 # 階層付きDF化 mult_index = pd.MultiIndex.from_product([["Degrees of Freedom"], vertical]) #縦軸の階層化 mult_column = pd.MultiIndex.from_product([["Probability"], horizon])# 横軸の階層化 DF = pd.DataFrame(chi_list, index =mult_index, columns= mult_column) DF
Probability 0.950 0.050 0.025 DOF 1 0.004 3.841 5.024 2 0.103 5.991 7.378 3 0.352 7.815 9.348 4 0.711 9.488 11.143 5 1.145 11.070 12.833 6 1.635 12.592 14.449
p73 F分布のグラフ(下側5%、上側5%)
import numpy as np import matplotlib.pyplot as plt from scipy import stats dfn = 9 # 分子の自由度 dfd = 6 # 分母の自由度 prob = 0.1 # 両裾の面積(確率) F_lower = stats.f.ppf(prob/2, dfn, dfd) # 下側確率のF値 F_upper = stats.f.ppf(1-prob/2, dfn, dfd) # 上側確率のF値 x_length = 6 plot_n =100 X_list = np.linspace(0, x_length, plot_n) #0から x_lengthまで plot_n個のリスト Y1 = stats.f.pdf(X_list,dfn, dfd) # F分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで plot_n個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"dfn={dfn} \ndfd={dfd}") # グラフを描画 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=F_upper),fc= 'lightgrey') plt.fill_between(X_list, Y1, Y2, where=(X_list<=F_lower),fc= 'lightgrey') plt.xlim(0, ) # 描画範囲を正の数に限定 plt.ylim(0, ) plt.title(f'F_Dist, Both_P={prob*100} % → F_low ={round(F_lower,2)}, F_up ={round(F_upper,2)}') # 表題 plt.xlabel('F') plt.legend() # 凡例 plt.show()
p73 F値の一覧表(上側5%)
import numpy as np from scipy import stats import pandas as pd prob = 0.1 dfns = np.linspace(1,10,10) # 横軸(分子の自由度) dfds = np.linspace(1,10,10) # 縦軸(分母の自由度) F_list = [] for dfd in dfds: Fvalues = [] for dfn in dfns: F_value = stats.f.ppf(1-prob/2,dfn, dfd) # 上側確率のF値 Fvalues.append(round(F_value,2)) # 各行を形成 F_list.append(Fvalues) # 各行を連結 # 階層付きDF化 mult_index = pd.MultiIndex.from_product([["DoD"], dfds]) #縦軸の階層化 mult_column = pd.MultiIndex.from_product([["Degrees of Numerator"], dfns])# 横軸の階層化 DF = pd.DataFrame(F_list, index =mult_index, columns= mult_column) DF
- 分子の自由度10、分母の自由度9について書籍73頁の表では「2.14」とあるが、正しくは「3.14」である。
p75~78 時計2つの遅れ進みデータ →ばらつき比を区間推定
import math from scipy.stats import f import statistics tick1 = [69,70,68,72,67,73,71] tick2 = [57,45,49,50,44,55,43,51,55,51] dfn = len(tick2)-1 dfd = len(tick1)-1 Nper = float(input('信頼区間[%]',)) pvalue = (100-Nper)/2/100 upper = f.ppf(1-pvalue, dfn, dfd) lower = f.ppf(pvalue, dfn, dfd) V1 = statistics.variance(tick1) V2 = statistics.variance(tick2) print(Nper,'%信頼区間:',round(1/math.sqrt(upper/(V2/V1)),3),'~',round(1/math.sqrt(lower/(V2/V1)),2))
信頼区間[%]95 95.0 %信頼区間: 0.956 ~ 4.67
p81 二項分布を正規分布で代用する
import numpy as np import math from scipy.stats import norm from scipy.stats import binom import matplotlib.pyplot as plt # 二項分布 n_attempts = 100 #試行回数 prob = 0.2 #成功確率 x_list = range(n_attempts) # 確率変数 x のリスト prob_d = binom(n_attempts, prob) # 確率分布 y_list = prob_d.pmf(x_list) # y のリスト plt.bar(x_list, y_list, color = 'grey', label = 'Binomial D') # 正規分布 mean = n_attempts * prob # 平均 sigma = math.sqrt(n_attempts * prob *(1-prob)) # 標準偏差 number = n_attempts X_list = np.linspace(0, number-1, number) #0から number-1 まで numbre個のリスト Y1 = norm.pdf(X_list,mean,sigma) # 確率密度関数のデータ Y2 = np.linspace(0,0,number) # 0から0まで number個のリスト(y=0 のデータ) plt.plot(X_list, Y1, color = 'red', label = 'Normal D') # 表示設定 plt.xlim(0,50) # 描画範囲を限定 plt.ylim(0,) plt.title(f'Binomial/Normal Distribution, attempts={n_attempts}, prob ={prob}') plt.legend() # 凡例 plt.show()
p79~83 標本の割合 →母集団の割合を区間推定
import math from scipy.stats import norm n = int(input('標本となる学生人数:',)) r = int(input('標本中の横浜ファンの人数:',)) p_h = r/n mu_h = n*p_h sigma_h =math.sqrt(n*p_h*(1-p_h)) print('p推定値:',p_h) print('μ推定値:',mu_h) print('σ推定値:',round(sigma_h,2)) # 割合pの区間推定 confidence_interval = float(input('信頼区間[%]:',)) accum_probability = 1-(50-confidence_interval/2)/100 upper = mu_h + norm.ppf(accum_probability)*sigma_h lower = mu_h - norm.ppf(accum_probability)*sigma_h print(f'割合pの区間推定:{round(lower,2)}~{round(upper,2)}%')
標本となる学生人数:100 標本中の横浜ファンの人数:30 p推定値: 0.3 μ推定値: 30.0 σ推定値: 4.58 信頼区間[%]:95 割合pの区間推定:21.02~38.98%
p87~90 標本の割合 →母集団の割合をF分布で区間推定
from scipy.stats import f n = int(input('標本数:',)) r = int(input('標本中の対象数:',)) phi1 = 2*(r+1) phi2 = 2*(n-r) phi1d = 2*(n-r+1) phi2d = 2*r confidence_interval = float(input('信頼区間[%]:',)) alpha_half = (100-confidence_interval)/2/100 F_a = f.ppf(1-alpha_half, phi1, phi2) F_b = f.ppf(1-alpha_half, phi1d, phi2d) P_up = phi1*F_a/(phi2+phi1*F_a) P_low = phi2d/(phi2d+phi1d*F_b) print('母集団中の割合pの',confidence_interval,'%信頼区間: ',round(P_low*100,2),'~',round(P_up*100,2),'%')
標本数:10 標本中の対象数:2 信頼区間[%]:95 母集団中の割合pの 95.0 %信頼区間: 2.52 ~ 55.61 %
p91 確率紙
import numpy as np from scipy.stats import f import matplotlib.pyplot as plt # 標本数 sn、信頼区間 ci sn = int(input('標本数:',)) ci = float(input('信頼区間 [%]:',)) # 関数: 標本数 sn、標本比率 sp、信頼区間 ci →母集団比率の信頼区間(F分布) def CI_by_F(sn,sp,ci): stn = sn*sp # 標本中の対象数 phi1 = 2*(stn+1) phi2 = 2*(sn-stn) phi1d = 2*(sn-stn+1) phi2d = 2*stn alpha_half = (100-ci)/2/100 # 信頼区間ci →F分布確率 F_a = f.ppf(1-alpha_half, phi1, phi2) F_b = f.ppf(1-alpha_half, phi1d, phi2d) P_up = phi1*F_a/(phi2+phi1*F_a) # 上限 P_low = phi2d/(phi2d+phi1d*F_b) # 下限 return P_low, P_up # 確率紙のグラフ SP = np.arange(0, 1, 0.001) # 標本中の比率の列 MPU = np.array([]) # 母集団中の比率上限の列 MPL = np.array([]) # 母集団中の比率下限の列 for sp in SP: mpl = CI_by_F(sn,sp,ci)[0] # 下限値を関数計算 MPL = np.append(MPL, mpl) mpu = CI_by_F(sn,sp,ci)[1] # 上限値を関数計算 MPU = np.append(MPU, mpu) plt.plot(SP, MPU, color='red') plt.plot(SP, MPL, color='blue') plt.grid(color='gray') plt.xlabel('Sample proportion') plt.ylabel('Population proportion')
標本数:10 信頼区間 [%]:90
4章 名行司ものがたり(検定のはなし)
p102~105 観客の反応と性別差
import math # 関数: # 男性x人のうちm人、女性y人のうちn人が失神する確率 def faint(x,m,y,n): return math.comb(x,m)*math.comb(y,n)/math.comb(x+y, m+n) # 女性が6人含まれる確率 x,m,y,n = [8,2,7,6] try1 = faint(x,m,y,n) # 女性が7人含まれる確率 x,m,y,n = [8,1,7,7] try2 = faint(x,m,y,n) # 合計の確率 prob_faint = try1+ try2 f'{round(try1*100,2)}%+{round(try2*100,2)}%={round(prob_faint*100,2)}%'
3.05%+0.12%=3.17%
p106~107 観客の反応と性別差(多人数版)
# 男性454人女性584人のうち失神者65人。同失神者の中に女性が44人以上含まれる確率 import math import pandas as pd allocation =[454,21,584,44] # 関数: # 男性x人のうちm人、女性y人のうちn人が失神する確率 def faint(x,m,y,n): return math.comb(x,m)*math.comb(y,n)/math.comb(x+y, m+n) addmax = allocation[2]-allocation[3] # 女性総数が女性失神者の増加上限 decmax = allocation[1]-0 # 0名が男性失神者の減少下限 limit = min(decmax,addmax) # 失神者の増減移動の限界 DF = pd.DataFrame(allocation) for m in range(limit): # 女性44人から65人の全場合をDF化 allocation[1] = allocation[1]-1 allocation[3] = allocation[3]+1 new_allo = pd.DataFrame(allocation) DF = pd.concat([DF,new_allo],axis=1) DF.index = ['Male','M_faint','Female','F_faint'] DF.columns=range(DF.shape[1]) print(DF) # 各場合の確率 Probability = [] for col in range(DF.shape[1]): # 列数だけ繰り返す prob = faint(DF[col]['Male'],DF[col]['M_faint'],DF[col]['Female'],DF[col]['F_faint']) Probability.append(prob) Prob = pd.DataFrame(Probability).T DF = pd.concat([DF, Prob]) DF.index = ['Male','M_faint','Female','F_faint','Probability'] sum = DF.loc['Probability'].sum() print(f'確率:{round(sum*100,2)}%')
p109~114 食い違いの検定
import pandas as pd import scipy.stats # 基礎データ DF = pd.DataFrame([ [200,8], [150,22], [100,15] ], index = ['Male', 'Female', 'Child'], columns = ['headcount','value']) headcount_sum = DF['headcount'].sum() # 縦合計値 value_sum = DF['value'].sum() # 縦合計値 # DF の形成 DF['expected'] = DF['headcount'] * value_sum / headcount_sum # 期待値 DF['difference'] = DF['value'] - DF['expected'] # 偏差 DF['square'] = DF['difference']**2 # 偏差の累乗 DF['Chi_square'] = DF['square']/DF['expected'] # 期待値で割る # # χ二乗値、自由度 →確率 Chi_2 = DF['Chi_square'].sum() # χ二乗値 dof = DF.shape[0]-1 # 自由度 prob = 1 - stats.chi2.cdf(Chi_2, dof) # 確率 # 参考(確率、自由度 →χ二乗値) prob_005 = 0.05 # 確率5% chi_005 = stats.chi2.ppf(1-prob_005, dof) # 確率5%の χ二乗値 print(f'本件:χ二乗値:{round(Chi_2,2)} の確率:{round(prob*100,3)} %') print(f'参考:χ二乗値:{round(chi_005,2)} の確率:{prob_005*100}%') DF
p111 適合度検定の関数(chisquare)を利用
import pandas as pd from scipy.stats import chisquare DF = pd.DataFrame([ [200,8], [150,22], [100,15] ], index = ['Male', 'Female', 'Child'], columns = ['headcount','value']) headcount_sum = DF['headcount'].sum() # 縦合計値 value_sum = DF['value'].sum() # 縦合計値 DF['expected'] = DF['headcount'] * value_sum / headcount_sum # 期待値 sta, pvalue = chisquare( DF['value'], DF['expected']) # 観察データ、期待値データ print(f'確率:{round(pvalue*100,3)}%') DF
p114 表4.2設例
import pandas as pd import math from scipy import stats # ----------------------------------------- 設定値の入力 m_h = int(input('男性:',)) m_f = int(input('男性の失神者:',)) f_h = int(input('女性:',)) f_f = int(input('女性の失神者:',)) # ----------------------------------------- χ二乗検定 DFX = pd.DataFrame([ [m_h,m_f], [f_h,f_f] ], index = ['Male', 'Female'], columns = ['headcount','value']) headcount_sum = DFX['headcount'].sum() value_sum = DFX['value'].sum() DFX['expected'] = round(DFX['headcount'] * value_sum / headcount_sum,1) # 有効数字3桁 DFX['difference'] = DFX['value'] - DFX['expected'] DFX['square'] = round(DFX['difference']**2,1) # 有効数字3桁 DFX['Chi_square'] = round(DFX['square']/DFX['expected'],2) # 有効数字3桁 # # χ二乗値、自由度 →確率 Chi_2 = round(DFX['Chi_square'].sum(),2) # 有効数字3桁 dof = DFX.shape[0]-1 # 自由度 kprob = 1-stats.chi2.cdf(Chi_2, dof) # 確率 # 参考(確率、自由度 →χ二乗値) prob_005 = 0.05 # 確率5% chi_005 = stats.chi2.ppf(1-prob_005, dof) # 確率5%の χ二乗値 # ----------------------------------------- 出力 print(f'本件:χ二乗値:{Chi_2}の確率:{round(kprob*100,2)}%') print(f'参考:χ二乗値:{round(chi_005,2)}の確率:{prob_005*100}%') DFX
p116 設例(コードは上述 p114 と同じ)
p116 適合度検定の関数(chisquare)を利用
DFXの[value][expected]列は上述 p114 と同じ
sta, pvalue = chisquare( DFX['value'], DFX['expected']) # 観察データ、期待値データ print(f'確率:{round(pvalue*100,2)}%')
確率:10.29%
p118 数値0~9の乱数表 の偏り
import numpy as np import pandas as pd import scipy.stats as stats from scipy.stats import chisquare # 基礎データ tenN = np.linspace(0,9,10) values = pd.Series([9,13,12,8,10,8,10,11,8,11]).T # DFの形成 DF = pd.DataFrame([tenN,values]).T DF.columns = ['Number','value'] Number_sum = DF['Number'].sum() # 縦合計値 value_sum = DF['value'].sum() # 縦合計値 DF['expected'] = value_sum / len(tenN) # 期待値 DF['difference'] = DF['value'] - DF['expected'] # 偏差 DF['square'] = DF['difference']**2 # 偏差の累乗 DF['Chi_square'] = DF['square']/DF['expected'] # 期待値で割る # χ二乗値、自由度 →確率 Chi_2 = DF['Chi_square'].sum() # χ二乗値 dof = DF.shape[0]-1 # 自由度 prob = 1 - stats.chi2.cdf(Chi_2, dof) # 確率 # chisquare で検算: sta, pvalue = chisquare( DF['value'], DF['expected']) # 観察データ、期待値データ # 参考(確率、自由度 →χ二乗値) prob_005 = 0.05 # 確率5% chi_005 = stats.chi2.ppf(1-prob_005, dof) # 確率5%の χ二乗値 # 出力 print(f'本件:χ二乗値:{round(Chi_2,2)} の確率:{round(prob*100,3)} %') print(f'本件:chisquare での確率:{round(pvalue*100,3)}%') print(f'参考:χ二乗値:{round(chi_005,2)} の確率:{prob_005*100}%') DF
p120 両側5%危険率の検定(数値0~9の乱数表)グラフ
import numpy as np import matplotlib.pyplot as plt from scipy import stats dof = 9 # 自由度 prob = 0.05 # 両裾の面積(確率) magni = 1.3 # グラフ対描画平面の拡大率 chi2_lower = stats.chi2.ppf(prob/2, dof) # 下側確率のχ二乗値 chi2_upper = stats.chi2.ppf(1-prob/2, dof) # 上側確率のχ二乗値 x_length = chi2_upper*magni plot_n =100 X_list = np.linspace(0, x_length, plot_n) #0から10で100個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで100個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=chi2_upper),fc= 'grey') plt.fill_between(X_list, Y1, Y2, where=(X_list<=chi2_lower),fc= 'grey') plt.xlim(0, chi2_upper*magni) # 描画範囲を正の数に限定 plt.ylim(0, max(Y1)*magni) # 描画範囲を限定 plt.title(f'Both Prob ={prob*100} % → ' r'$\chi^2$' f'=low_{round(chi2_lower,3)}, up_{round(chi2_upper,2)}') # 表題 plt.xlabel(r'$\chi^2$') plt.legend() # 凡例 plt.show()
p120 片側5%危険率の検定(数値0~9の乱数表)グラフ
# import 文は、上記と同様 # chi2_lower, chi2_upperは、上記設例(両側検定の上側確率)を使用 dof = 9 # 自由度 oneside_prob = 0.05 # 片側の面積(確率) magni = 1.3 # 縦拡大率 chi2_lower_s = stats.chi2.ppf(oneside_prob, dof) # 下側確率のχ二乗値 chi2_upper_s = stats.chi2.ppf(1-oneside_prob, dof) # 上側確率のχ二乗値 x_length = chi2_upper*magni # 描画の横範囲を両側検定にあわせる plot_n =100 X_list = np.linspace(0, x_length, plot_n) #0から10で100個のリスト Y1 = stats.chi2.pdf(X_list,dof) # χ二乗分布の確率密度関数のリスト Y2 = np.linspace(0,0,plot_n) # 0から0まで100個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 # 塗りつぶし plt.fill_between(X_list, Y1, Y2, where=(X_list>=chi2_upper_s),fc= 'blue') plt.fill_between(X_list, Y1, Y2, where=(X_list<=chi2_lower_s),fc= 'orange') plt.fill_between(X_list, Y1, Y2, where=(X_list>=chi2_upper),fc= 'grey') # 両側検定の描画 plt.fill_between(X_list, Y1, Y2, where=(X_list<=chi2_lower),fc= 'grey') # 両側検定の描画 plt.xlim(0, chi2_upper*magni) # 描画の横範囲を両側検定にあわせる plt.ylim(0, max(Y1)*magni) # 描画の縦範囲を限定 plt.title(f'One_Sided_Prob ={oneside_prob*100} % → ' r'$\chi^2$' f'=low_{round(chi2_lower_s,2)}, up_{round(chi2_upper_s,2)}') # 表題 plt.xlabel(r'$\chi^2$') plt.legend() # 凡例 plt.show()
p120 平均値を検定する
gram = pd.Series([94,97,98,99,102,98]) # 標本値 m_average = 100 # 母平均(仮説) side_prob = 0.05 # 片側確率(確率) s_average = gram.mean() # 標本平均 s_s = gram.std(ddof=0) # 標本標準偏差 numbers = len(gram) # 要素数 dof = numbers -1 # 自由度 t_value = -stats.t.ppf(side_prob, dof) # 片側確率のt値 myu_up = s_average + t_value * (s_s/math.sqrt(numbers-1)) # t値対応のx上限 def t_func(sa,ma,ss,num): # t値を求める関数 return (sa - ma)/(ss/math.sqrt(num-1)) tva = -t_func(s_average,m_average,s_s,numbers) # t値 prob = stats.t.sf(tva, df = numbers-1) # t値に対応する上側確率 # t検定の結果表示 if prob>= 0.05: print(f't : {round(tva,2)} < {round(t_value,3)}') else: print(f't : {round(tva,2)} > {round(t_value,3)}') if prob>= 0.05: print(f'weight : {round(m_average)} < {round(myu_up,3)}') else: print(f'weight : {round(m_average)} > {round(myu_up,3)}') if prob>= 0.05: print(f'side_prob:{round(prob*100,1)}% > {side_prob*100}%,\n then the hypothesis [μ={m_average}g] is Not rejected.') else: print(f'side_prob:{round(prob*100,1)}% < {side_prob*100}%,\n then the hypothesis [μ={m_average}g] is Rejected.') # グラフ表記 X_list = np.linspace(95, 101, 100) #95から101で100個のリスト Y1 = stats.t.pdf(X_list,dof,s_average) # t分布の確率密度関数のリスト Y2 = np.linspace(0,0,100) # 0から0まで100個のリスト(y=0 のデータ) plt.plot(X_list, Y1, label=f"Φ={dof}") # グラフを描画 plt.fill_between(X_list, Y1, Y2, where=(X_list>=myu_up),fc= 'lightgrey') # 塗りつぶし plt.xlim(95,101) # 描画領域設定 plt.ylim(0,) # 描画領域設定 plt.vlines(s_average,0,stats.t.pdf(0,dof), color = 'blue') # 標本平均の場所に縦線 plt.vlines(m_average,0,stats.t.pdf(m_average-s_average,dof), color = 'red') # 母平均(仮説値)の場所に縦線 plt.title(f'TD, Upper_Side_Prob={side_prob*100}% → weight_upper={round(myu_up,3)}') # 表題 plt.legend() # 凡例 plt.show()
t : 1.88 < 2.015 weight : 100 < 100.145 side_prob:6.0% > 5.0%, then the hypothesis [μ=100g] is Not rejected.
p125 ばらつきを検定する
import numpy as np import statistics as stat from scipy import stats savings = np.array([10,10,30,30]) # 標本 sigma = 30 # 母標準偏差(仮定) prob = 0.05 # 危険率 dof = len(savings)-1 # 自由度 ss = stat.pstdev(savings) # 標本の標準偏差 smean = stat.mean(savings) # 標本の平均 sum_squ = sum((s - smean)**2 for s in savings) # 標本の平方和 chi2_h = sum_squ/sigma**2 # 帰無仮説下でのχ二乗値 chi2 = stats.chi2.ppf(prob, dof) # 下側確率のχ二乗値 print(f'標本{savings}の標準偏差は{ss}。\n帰無仮説(母標準偏差{sigma})を危険率{prob*100}%で検定。') print(f'帰無仮説下でのχ二乗値:{round(chi2_h,2)}\n下側確率{prob*100}%のχ二乗値:{round(chi2,2)}') if chi2_h > chi2: print('帰無仮説は維持。') else: print('帰無仮説を棄却。')
標本[10 10 30 30]の標準偏差は10.0。 帰無仮説(母標準偏差30)を危険率5.0%で検定。 帰無仮説下でのχ二乗値:0.44 下側確率5.0%のχ二乗値:0.35 帰無仮説は維持。
p127 ばらつきの比率を検定する
import pandas as pd tick1 = [69,70,68,72,67,73,71] tick2 = [57,45,49,50,44,55,43,51,55,51] prob = 0.05 # 危険率 def statistic(list): length = len(list) # 標本数 smean = stat.mean(list) # 標本の平均 ss = round(stat.pstdev(list),2) # 標本の標準偏差 ubv = round(length/(length-1) * ss**2,1) # 標本の不偏分散 return length, smean, ss, ubv # DataFrame の形成 DF = pd.DataFrame([statistic(tick1), statistic(tick2)], index = ['tick1','tick2'], columns = ['Numbers','Mean','Standard Dev','Unbiased Var']).T F_value_h = DF['tick2']['Unbiased Var']/DF['tick1']['Unbiased Var'] # 帰無仮説下でのF値 F_value = stats.f.ppf(0.95, DF['tick2']['Numbers']-1, DF['tick1']['Numbers']-1) # 上側確率のF値 print(f'帰無仮説(2つの時計にばらつき無し)を危険率{prob*100}%で片側検定。') print(f'帰無仮説下でのF値:{round(F_value_h,2)} \n上側確率{prob*100}%のF値:{round(F_value,2)}') if F_value_h < F_value: print('帰無仮説は維持。') else: print('帰無仮説を棄却。') DF
帰無仮説(2つの時計にばらつき無し)を危険率5.0%で片側検定。 帰無仮説下でのF値:5.0 上側確率5.0%のF値:4.1 帰無仮説を棄却。 tick1 tick2 Numbers 7.0 10.0 Mean 70.0 50.0 Standard Dev 2.0 4.6 Unbiased Var 4.7 23.5
p130 パーセンテージを検定する
import math mtv = 230 # 該番組を見たTV台数 ntv = 618 # TV台数 pratings = 0.3 # 母集団の視聴率(仮定) sratings = round(mtv/ntv,3) # 標本の視聴率 prob = 0.05 # 危険率 kh = (sratings - pratings) / math.sqrt(sratings*(1-sratings)/ntv) # 帰無仮説下でのz値 kt = stats.norm.ppf(1-prob) # 上側確率のz値 print(f'標本の視聴率:{sratings*100}%。\n帰無仮説(母集団の視聴率{pratings*100}%)を危険率{prob*100}%で検定。') print(f'帰無仮説下でのz値:{round(kh,3)}\n上側確率{prob*100}%のz値:{round(kt,3)}') if kh < kt: print('帰無仮説は維持。') else: print('帰無仮説を棄却。')
標本の視聴率:37.2%。 帰無仮説(母集団の視聴率30.0%)を危険率5.0%で検定。 帰無仮説下でのz値:3.703 上側確率5.0%のz値:1.645 帰無仮説を棄却。