「統計解析のはなし―データに語らせるテクニック」7章
大村平「統計解析のはなし―データに語らせるテクニック」日科技連 の読後行間補充メモ
同書籍は、印刷数表と手計算による統計解析を紹介した良書。
本稿では、同書籍の設例について、プログラムによる演算処理をした場合の例を示す。
コードと出力例は、Python[Google Colaboratory]
7章 総身に知恵はまわるのか ~相関と回帰のはなし~
p201~204 正の相関/負の相関/相関なし
import pandas as pd index_info = ['By_Kou','By_Otsu'] # 共通 col_info = ['A','B','C','D','E'] # 共通 # 表7.1 DF = pd.DataFrame([[5,4,3,2,1], [5,4,3,2,1]], index = index_info, columns = col_info) DF.loc['multiplied'] = DF.loc['By_Kou'] * DF.loc['By_Otsu'] squared_sum = DF.loc['multiplied'].sum() print(f'表7.1\n{DF}') print(f'積和:{squared_sum}') # 表7.2 DF2 = pd.DataFrame([[5,4,3,2,1], [1,2,3,4,5]], index = index_info, columns = col_info) DF2.loc['multiplied'] = DF2.loc['By_Kou'] * DF2.loc['By_Otsu'] squared_sum = DF2.loc['multiplied'].sum() print(f'\n表7.2\n{DF2}') print(f'積和:{squared_sum}') # 表7.3 DF3 = pd.DataFrame([[5,4,3,2,1], [4,1,3,5,2]], index = index_info, columns = col_info) DF3.loc['multiplied'] = DF3.loc['By_Kou'] * DF3.loc['By_Otsu'] squared_sum = DF3.loc['multiplied'].sum() print(f'\n表7.3\n{DF3}') print(f'積和:{squared_sum}')
表7.1 A B C D E By_Kou 5 4 3 2 1 By_Otsu 5 4 3 2 1 multiplied 25 16 9 4 1 積和:55 表7.2 A B C D E By_Kou 5 4 3 2 1 By_Otsu 1 2 3 4 5 multiplied 5 8 9 8 5 積和:35 表7.3 A B C D E By_Kou 5 4 3 2 1 By_Otsu 4 1 3 5 2 multiplied 20 4 9 10 2 積和:45
p207 表7.4
順位の相関を求めるための数表
import pandas as pd # 関数の定義 def max_calc(number): # 最大値 return(number*(number+1)*(2*number+1)/6) def mini_calc(number): # 最小値 return(number*(number+1)*(number+2)/6) def median_calc(number): # 中央値 return((max_calc(number)+mini_calc(number))/2) def divise_calc(number): # 除数 return(max_calc(number) -median_calc(number)) # 項目用空リスト numbers = [] max = [] min = [] deduct = [] divisor = [] # 各項目を関数で計算して、リストに格納 for n in range(2, 9, 1): # n を2~8で生成 numbers.append(n) max.append(max_calc(n)) min.append(mini_calc(n)) deduct.append(median_calc(n)) divisor.append(divise_calc(n)) DF = pd.DataFrame([numbers,max,min,deduct,divisor]).T # 結果をDFに整理 DF.columns=['Number','Max','Min','Deduct','Divisor'] DF # 表7.4
Number Max Min Deduct Divisor 0 2.0 5.0 4.0 4.5 0.5 1 3.0 14.0 10.0 12.0 2.0 2 4.0 30.0 20.0 25.0 5.0 3 5.0 55.0 35.0 45.0 10.0 4 6.0 91.0 56.0 73.5 17.5 5 7.0 140.0 84.0 112.0 28.0 6 8.0 204.0 120.0 162.0 42.0
p210 図7.1 順位相関を目で見る 表7.1の場合
# 図7.1 import pandas as pd import matplotlib.pyplot as plt index_info = ['By_Kou','By_Otsu'] col_info = ['A','B','C','D','E'] # 表7.1 DF71 = pd.DataFrame([[5,4,3,2,1], [5,4,3,2,1]], index = index_info, columns = col_info) y = DF71.loc['By_Kou'] # グラフxデータ x = DF71.loc['By_Otsu'] # グラフyデータ plt.scatter(x, y,s=300) plt.xlabel(index_info[1]) plt.ylabel(index_info[0]) plt.plot([3, 3], [0, 6], color="black") #縦線 x=3 plt.plot([0, 6], [3, 3], color="black") #横線 y=3 plt.grid(True) plt.title('Chart_71') plt.show()
p210 図7.1 順位相関を目で見る 208頁の場合
# コードは上記の続き DF208 = pd.DataFrame([[5,4,3,2,1], [4,3,5,1,2]], index = index_info, columns = col_info) y = DF208.loc['By_Kou'] # グラフxデータ x = DF208.loc['By_Otsu'] # グラフyデータ plt.scatter(x, y,s=300) plt.xlabel(index_info[1]) plt.ylabel(index_info[0]) plt.plot([3, 3], [0, 6], color="black") #縦線 x=3 plt.plot([0, 6], [3, 3], color="black") #横線 y=3 plt.grid(True) plt.title('Chart_208')
p211 相関係数 表7.5
学科得点とスポーツ成績の相関
import pandas as pd import math import matplotlib.pyplot as plt # 基礎データ index_info = ['Academics_Score','Sports_Score'] col_info = ['A','B','C','D','E','F'] DF75 = pd.DataFrame([[6,5,9,9,6,7], [5,5,7,8,4,7]], index = index_info, columns = col_info) DF75T = DF75.T DF75T
p213 図7.3 座標の原点をデータの中心へ
第1象限と第3象限にある点は、\(x\times y\) 値がプラスになる(正の相関判定に利用)。
# グラフ化 x = DF75.loc['Academics_Score'] y = DF75.loc['Sports_Score'] plt.scatter(x, y,s=200) plt.xlabel('Academics_Score') plt.ylabel('Sports_Score') # 平均線 x_ave = DF75.loc['Academics_Score'].mean() y_ave = DF75.loc['Sports_Score'].mean() plt.plot([x_ave, x_ave], [0, 10], color="black") #縦線 xの平均 plt.plot([0, 10], [y_ave, y_ave], color="black") #横線 yの平均 plt.grid(True) plt.title('Chart_71') plt.show()
p215 表7.6 相関係数を求めるために
# 前提計算 DF75T['A_deviation'] = DF75T['Academics_Score']-x_ave DF75T['S_deviation'] = DF75T['Sports_Score']-y_ave DF75T['A_dev_squ'] = DF75T['A_deviation']**2 DF75T['S_dev_squ'] = DF75T['S_deviation']**2 DF75T['numerator'] = DF75T['A_deviation'] *DF75T['S_deviation'] DF75R = DF75T.reindex(columns=['Academics_Score', 'A_deviation', 'A_dev_squ','Sports_Score', 'S_deviation', 'S_dev_squ','numerator']) #列の並びを変更 DF75R.loc['Sum'] = DF75R.sum() # 相関係数 Denominator = math.sqrt(DF75R['A_dev_squ']['Sum'] *DF75R['S_dev_squ']['Sum']) Numerator = DF75R['numerator']['Sum'] Corr = Numerator/Denominator print(f'correlation:{round(Corr,3)}') # DFの表示 DF75R
p215 Pandas の関数 corr を使用した場合
# 既存関数での計算 import pandas as pd Academic = pd.Series([6,5,9,9,6,7]) Sports = pd.Series ([5,5,7,8,4,7]) res = Academic.corr(Sports) print(f'correlation:{round(res,3)}')
correlation:0.849
p216 相関係数の区間推定
標本から求めた相関係数 →母集団における相関係数を区間推定
import math from scipy.stats import norm import matplotlib.pyplot as plt alpha = 0.05 # 危険率 n6 = 6 # 標本数 n30 = 30 # 標本数 # 関数 フィッシャーの z変換 def fisher(ratio): #標本の相関係数 z2 = math.log((1+ratio)/(1-ratio)) return z2/2 # 関数 確率 →パーセント値 def p_value(alpha): # 危険率 percent = norm.ppf(q = 1-alpha/2, loc=0) # 正規分布のp%点 return percent # パーセント値 # 母集団の相関係数の上側 def Upper(ratio, alpha, numbers): # 標本の相関係数、危険率、標本数 zvalue = fisher(ratio) # フィッシャーの z 変換関数を使用 percent = p_value(alpha) # パーセント値を求める関数を使用 up = zvalue + percent * math.sqrt(1/(numbers-3)) Upper= (math.exp(2*up)-1)/(math.exp(2*up)+1) # 上側を求める関数 return Upper # 母集団の相関係数の下側 def Lower(ratio,alpha,numbers): # 標本の相関係数、危険率、標本数 zvalue = fisher(ratio) percent = p_value(alpha) low = zvalue - percent * math.sqrt(1/(numbers-3)) Low= (math.exp(2*low)-1)/(math.exp(2*low)+1) return Low # グラフ用データ列を用意 x_row = [] y6_u_row = [] # 標本数6の場合の上限データ用 y6_l_row = [] # 標本数6の場合の下限データ用 y30_u_row = [] y30_l_row = [] for rate in range(-99,100,1): x_row.append(rate/100) y6_u_row.append(Upper(rate/100,alpha,n6)) # 上限関数で計算 y6_l_row.append(Lower(rate/100,alpha,n6)) # 下限関数で計算 y30_u_row.append(Upper(rate/100,alpha,n30)) y30_l_row.append(Lower(rate/100,alpha,n30)) # 色を指定 colors = ["blue", "blue", "red", "red"] plt.gca().set_prop_cycle(color=colors) # グラフを描画 plt.plot(x_row, y6_u_row, label=f'n = {n6}') # 標本数6の上側グラフ plt.plot(x_row, y6_l_row) # 標本数6の下側グラフ plt.plot(x_row, y30_u_row, label=f'n = {n30}') plt.plot(x_row, y30_l_row) plt.grid() # 罫線 plt.title(f'{(1-alpha)*100}% Interval Estimation') # 表題 plt.xlabel("r = Correlation coefficient of the Sample") # x軸の名称 plt.ylabel("Correlation coefficient of the Population") plt.legend() # 凡例 plt.show()
p217~218 事例
# 事例 ratio = 0.85 # 217頁設例 numbers = n6 up6_95 = Upper(ratio,alpha,numbers) lo6_95 = Lower(ratio,alpha,numbers) print(f'標本数{numbers}で相関係数{ratio}のとき、母集団の相関係数の{(1-alpha)*100}%信頼区間は、{round(lo6_95,2)}~{round(up6_95,2)}') ratio = 0.85 numbers = 50 # 217頁設例 up50_95 = Upper(ratio,alpha,numbers) lo50_95 = Lower(ratio,alpha,numbers) print(f'標本数{numbers}で相関係数{ratio}のとき、母集団の相関係数の{(1-alpha)*100}%信頼区間は、{round(lo50_95,2)}~{round(up50_95,2)}') ratio = 0.81 # 218頁設例 numbers = n6 up6_95 = Upper(ratio,alpha,numbers) lo6_95 = Lower(ratio,alpha,numbers) print(f'標本数{numbers}で相関係数{ratio}のとき、母集団の相関係数の{(1-alpha)*100}%信頼区間は、{round(lo6_95,2)}~{round(up6_95,2)}')
標本数6で相関係数0.85のとき、母集団の相関係数の95.0%信頼区間は、0.12~0.98 標本数50で相関係数0.85のとき、母集団の相関係数の95.0%信頼区間は、0.75~0.91 標本数6で相関係数0.81のとき、母集団の相関係数の95.0%信頼区間は、-0.0~0.98
p219 相関は因果関係を保証しない
import pandas as pd import math from scipy import stats # 設例データ tall = [120,130,135,140,150,160,165,170,175,180] mathematics = [13,28,35,60,55,72,90,80,84,83] alpha = 1-0.95 # 信頼確率95% # リストを Seriesに変換 s_tall = pd.Series(tall) s_math = pd.Series(mathematics) # 標本の相関係数を計算 res = s_tall.corr(s_math) print(f'標本の相関係数:{round(res,3)}') # 関数 集団の相関係数の信頼区間 def Conf_int(alpha, num, res): # 信頼確率、標本数、標本の相関係数 zvalue = (math.log((1+res)/(1-res)))/2 # フィッシャーのz変換 pvalue = stats.norm.ppf(1-alpha/2, loc=0) # p値 # 母集団の相関係数の下側 low = zvalue - pvalue * math.sqrt(1/(num-3)) Lower= (math.exp(2*low)-1)/(math.exp(2*low)+1) # 母集団の相関係数の上側 up = zvalue + pvalue * math.sqrt(1/(num-3)) Upper= (math.exp(2*up)-1)/(math.exp(2*up)+1) return [Lower, Upper] # 集団の相関係数を計算 Lower = Conf_int(alpha, len(tall),res)[0] Upper = Conf_int(alpha, len(tall),res)[1] print(f'母集団の相関係数の {(1-alpha)*100}%区間推定:{round(Lower,3)}~{round(Upper,3)}') # DF化 DF = pd.DataFrame([tall,mathematics]).T DF.columns=['tall','mathematics'] DF
標本の相関係数:0.946 母集団の相関係数の 95.0%区間推定:0.783~0.987 tall mathematics 0 120 13 1 130 28 2 135 35 3 140 60 4 150 55 5 160 72 6 165 90 7 170 80 8 175 84 9 180 83
p220 相関は因果関係を保証しない(身長160cm以上に限定)
# コードは上記の続き # 特定の身長以上の列を抽出 limit = 160 DF_limit = DF[DF['tall'] >= limit] # 標本の相関係数を求める limit_tall = pd.Series(DF_limit['tall']) limit_math = pd.Series(DF_limit['mathematics']) res_limit = limit_tall.corr(limit_math) print(f'身長{limit}cm以上の標本の相関係数:{round(res_limit,3)}') # 集団の相関係数を計算 Lower = Conf_int(alpha, DF_limit.shape[0],res_limit)[0] Upper = Conf_int(alpha, DF_limit.shape[0],res_limit)[1] print(f'母集団の相関係数の {(1-alpha)*100}%区間推定:{round(Lower,3)}~{round(Upper,3)}') DF_limit
身長160cm以上の標本の相関係数:0.385 母集団の相関係数の 95.0%区間推定:-0.753~0.946 tall mathematics 5 160 72 6 165 90 7 170 80 8 175 84 9 180 83
p223 直線で回帰する 表7.8
import pandas as pd import math # 設例データ year = [1985,1990,1995,1997,1999,2001] Drowning_Deaths = [2004,1479,1214,1243,1179,1058] # 相関係数 year_s = pd.Series(year) DD_s = pd.Series(Drowning_Deaths) res = year_s.corr(DD_s) print(f'相関係数:{round(res,3)}') # DF化 DF = pd.DataFrame([year,Drowning_Deaths]).T DF.columns=['Year','Drowning_Deaths'] DF
相関係数:-0.954 Year Drowning_Deaths 0 1985 2004 1 1990 1479 2 1995 1214 3 1997 1243 4 1999 1179 5 2001 1058
p223 直線で回帰する 図7.6
# コードは上記の続き from matplotlib import pyplot as plt plt.plot(year,Drowning_Deaths) plt.xlabel('Year') plt.ylabel('Drowning_Deaths') plt.xlim(1984,2002) plt.ylim(800,2100) plt.show()
p228 回帰直線 表7.9
# コードは上記の続き DF['x'] = DF['Year']-1980 DF['y'] = DF['Drowning_Deaths']-1000 DF['xy'] = DF['x']*DF['y'] DF['x^2'] = DF['x']**2 DF.loc['Sum'] = DF.sum() # 傾き a angle = (DF['xy']['Sum']-DF['x']['Sum']*DF['y']['Sum']/len(year))/(DF['x^2']['Sum']-DF['x']['Sum']**2/len(year)) print(f'傾き a:{round(angle,2)}') # 切片 b intercept_b = DF['Drowning_Deaths']['Sum']/len(year) - round(angle,1) *DF['Year']['Sum']/len(year) print(f'切片 b:{round(intercept_b,2)}') DF
傾き a:-54.58 切片 b:110262.53 Year Drowning_Deaths x y xy x^2 0 1985 2004 5 1004 5020 25 1 1990 1479 10 479 4790 100 2 1995 1214 15 214 3210 225 3 1997 1243 17 243 4131 289 4 1999 1179 19 179 3401 361 5 2001 1058 21 58 1218 441 Sum 11967 8177 87 2177 21770 1441
p228 回帰直線 グラフ
# コードは上記の続き plt.scatter(year,Drowning_Deaths) x_s = [] y_s = [] for i in range(1980,2012): x_s.append(i) y_s.append(i*angle+intercept_b) plt.plot(x_s,y_s) plt.xlim(1984,2012) plt.ylim(400,2200)