「統計解析のはなし―データに語らせるテクニック」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
帰無仮説を棄却。