「統計解析のはなし―データに語らせるテクニック」9章
大村平「統計解析のはなし―データに語らせるテクニック」日科技連 の読後行間補充メモ
同書籍は、印刷数表と手計算による統計解析を紹介した良書。
本稿では、同書籍の設例について、プログラムによる演算処理をした場合の例を示す。
コードと出力例は、Python[Google Colaboratory]
9章 なんでも数字で表す法 ~数量化のはなし~
p262 5段階評価 表9.1
- 等間隔目盛りで評価対象を測定する線形の評価。
- 平均値をまたいだ \(1\sigma\) の区間に約38パーセントの確率分布。
import numpy as np from scipy.stats import norm import pandas as pd import matplotlib.pyplot as plt p_inf = float('inf') # 無限大 # 設定値 mean = 0 # 平均 sigma = 1 # 標準偏差 # 領域の上限 up1 = -sigma *3/2 up2 = -sigma/2 up3 = sigma/2 up4 = sigma *3/2 up5 = p_inf up_list = [-p_inf, up1, up2, up3, up4, up5] # リスト化 # 領域の確率 area_prob = [] for up in range(len(up_list)-1): prob = norm.cdf(up_list[up+1], mean)-norm.cdf(up_list[up], mean) area_prob.append(round(prob*100,1)) # DF化 ## index生成 subject = "{}点クラス" point_list = ['1','2','3','4','5'] index_info = [] for point in point_list: class_name = subject.format(point) # 差込で語句生成 index_info.append(class_name) ## DF生成 DFw = pd.DataFrame([area_prob]) DF = DFw.T DF.index =[index_info] DF.columns =['確率 [%]'] # グラフのデータ X_list = np.linspace(-3, 2.9, 60) # -3から2.9まで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.xticks([up_list[1],up_list[2],up_list[3],up_list[4]], [r'$-\frac{3}{2}\sigma$',r'$-\frac{1}{2}\sigma$',r'$\frac{1}{2}\sigma$', r'$\frac{3}{2}\sigma$' ]) # x軸目盛 plt.yticks([]) plt.title('5 stage evaluation') # 表題 plt.ylim(0,) # 塗りつぶし color_list = ['lightgrey','lightblue','lightgreen','orange'] for num in range(len(color_list)): plt.fill_between(X_list, Y1, Y2, where=(X_list>=up_list[num+1]),fc= color_list[num]) # 表示 print(DF) plt.show() 確率 [%] 1点クラス 6.7 2点クラス 24.2 3点クラス 38.3 4点クラス 24.2 5点クラス 6.7
p267 ウェイト付け(1次元に圧縮) 表9.2
- 2次元(例:年齢・扶養家族)の組合せにつき優劣を設定し、点数を割り振る。[表9.2の各上段]
- 同組合せを構成している各次元内での項目(例:年齢であれば、若・老)に点数を配賦する。[表9.2の各下段]
- 上記工程を3種(3次元のうち2次元を選び出す組合せの数)実施し、各次元内での項目ごとに合計点数を集計する(例:年齢=老であれば、4点)
- 評価対象(例:A曹長)ごとに、各次元(例:年齢)の該当項目(例:年齢=老)に該当する点数(例:4点)を与えて、評価対象ごとに点数を集計する(例:A曹長であれば15点)。[表9.3]
- 同評価対象の集計点数の多寡により、評価対象の優劣を判定する(1次元判定)。
import pandas as pd # 考慮要素 Age = ['若','老'] Depend = ['有','無'] Services = ['長', '短'] elements = [Age, Depend, Services] # リスト化 profile = {'年齢': Age, '扶養家族': Depend, '勤務年数': Services} # 辞書 # ------------------------------------------------------表9.2 を作るための関数 def score_cal(i,j): # 考慮要素を組み合わせた軸要素を作成 comblist = [] for iele in elements[i]: for jele in elements[j]: comblist.append(iele +'・'+ jele) # 空のDF作成 DF92part = pd.DataFrame(index =comblist, columns =comblist) # 斜線右上を設定 DF92part.iloc[0][1:4] = 1 if i==1 and j==2: DF92part.iloc[1][2] = 1 # (i,j)=(1,2)のときは、1 else: DF92part.iloc[1][2] = -1 # (i,j)=(0,1) or (0,2) のときは、-1 DF92part.iloc[1][3] = 1 DF92part.iloc[2][3] = 1 # 斜線右上の値を反転して左下に入力 for col in range(0,DF92part.shape[1]): # 列数だけ繰り返す for row in range(0,DF92part.shape[0]): # 行数だけ繰り返す DF92part.iloc[row][col] = -DF92part.iloc[col][row] # 表示設定 DF92part = DF92part.replace(1, '〇') DF92part = DF92part.replace(-1, '×') # 〇の個数合計の列を追加 DF_bool = (DF92part == '〇') # 〇判定 bool_sum = DF_bool.sum(axis =1) # 列ごとのTrue 数を集計 bool_col = pd.DataFrame([bool_sum], index = ['点数']).T # 〇個数の列 DF92part = pd.concat([DF92part,bool_col], axis=1) # 関数 列名の特定文字に点数を与える def collect(str): nstr = 0 for row in range(4): if str in DF92part.index[row]: nstr += DF92part.iloc[row][4] return nstr # 集計 ele_i0 = collect(elements[i][0]) # 考慮要素内の有利特性の点数 ele_i1 = collect(elements[i][1]) # 考慮要素内の有利特性の点数 ele_j0 = collect(elements[j][0]) ele_j1 = collect(elements[j][1]) ele_DF = pd.DataFrame([ele_i0, ele_i1, ele_j0, ele_j1] , columns=[f'{list(profile.keys())[i]} & {list(profile.keys())[j]}の点数'] , index=[elements[i][0], elements[i][1], elements[j][0],elements[j][1]]) # 戻り値 return DF92part, ele_DF # 一覧表DF、考慮要素内の各特性の点数DF # -------------------------------- score_cal関数への入力と出力表示のための関数 def DF_maker(ignore): # 関数 score_cal関数に入力する(i,j)の組の選別 BL = [0,1,2] BL.remove(ignore)# (0,1), (0,2), (1,2) # 演算と表示 print(f'→ {list(profile.keys())[ignore]}を無視\n') # (i,j)=(0,1) display(score_cal(BL[0],BL[1])[0]) # 一覧表DF display(score_cal(BL[0],BL[1])[1]) # 考慮要素内の各特性の点数DF # -------------------------------------------------------------------------- # 実行 ignore = int(input(f'年齢=0, 扶養家族=1, 勤続年数=2 のいずれかを入力: ', )) DF_maker(ignore)
年齢=0, 扶養家族=1, 勤続年数=2 のいずれかを入力: 2 → 勤務年数を無視 若・有 若・無 老・有 老・無 点数 若・有 NaN 〇 〇 〇 3 若・無 × NaN × 〇 1 老・有 × 〇 NaN 〇 2 老・無 × × × NaN 0 年齢 & 扶養家族の点数 若 4 老 2 有 5 無 1 年齢=0, 扶養家族=1, 勤続年数=2 のいずれかを入力: 1 → 扶養家族を無視 若・長 若・短 老・長 老・短 点数 若・長 NaN 〇 〇 〇 3 若・短 × NaN × 〇 1 老・長 × 〇 NaN 〇 2 老・短 × × × NaN 0 年齢 & 勤務年数の点数 若 4 老 2 長 5 短 1 年齢=0, 扶養家族=1, 勤続年数=2 のいずれかを入力: 0 → 年齢を無視 有・長 有・短 無・長 無・短 点数 有・長 NaN 〇 〇 〇 3 有・短 × NaN 〇 〇 2 無・長 × × NaN 〇 1 無・短 × × × NaN 0 扶養家族 & 勤務年数の点数 有 5 無 1 長 4 短 2
p268 3つの表[表9.2]から点数を集計
# コードは上記の続き Weight_DF = pd.concat([score_cal(0,1)[1],score_cal(0,2)[1],score_cal(1,2)[1]], axis=1) Weight_DF['合計'] = Weight_DF.sum(axis=1, skipna=True) Weight_DF
p268 各人の得点を求める 表9.3
# コードは上記の続き import numpy as np DF93 = pd.DataFrame([Weight_DF.index.values.tolist() ,Weight_DF['合計'].values.tolist() ,['','レ','','レ','レ',''] ,['レ','','レ','','','レ'] ,['','レ','レ','','','レ']] ,index=['カテゴリ','ウェイト','A曹長','B二等兵','C軍曹']) DF93_bool = (DF93 == 'レ') # レ判定 scores_list = [] for person in range(2,DF93.shape[0]): score = 0 for score_col in range(DF93.shape[1]): cell = DF93_bool.iloc[person][score_col] if cell == True: score += DF93.iloc[1][score_col] #該当行のウェイト数値を加算 scores_list.append(score) bool93_col = pd.DataFrame([scores_list], columns =DF93.index[2:5]).T DF93 = pd.concat([DF93,bool93_col], axis=1) DF93.columns = ['年齢','年齢','扶養家族','扶養家族','勤務年数','勤務年数','得点'] DF93 = DF93.fillna('') DF93
p269 基準が数値で与えられたら [数量化 Ⅰ 類] 表9.4
- 外的基準が数値で付与。←→外的基準が分類で付与(数量化Ⅱ類)
- 2次元の情報を1次元の数値に数量化。
- 各次元(例:学科)の項目(例:学科であれば優・並)ごとに重みを変数(例:学科=優であれば、\(x_1\))で設定 [表9.5]
- 評価対象(例:甲)ごとに予測値(例:\(x_1+y_1+c\)) を設定 [表9.5]
- 予測値と外的数値基準(例:甲であれば5点)とが最も適合するように、最小二乗法で、重み変数を定める。(二乗和をした式[式9.3]の各偏微分式[式9.4]が0になるように連立方程式を解く)
- 求めた重み変数(\(x_1,x_2,y_1,y_2\))を用いて、評価対象ごとの予想得点を求める(1次元化)
import pandas as pd index_info =['甲','乙','丙','丁','戊'] DF94 = pd.DataFrame([['優','優',5] ,['優','優',3] ,['優','並',1] ,['並','優',4] ,['並','優',2]] , index = index_info , columns =['学科試験','面接試験','入社後の実績']) DF94 学科試験 面接試験 入社後の実績 甲 優 優 5 乙 優 優 3 丙 優 並 1 丁 並 優 4 戊 並 優 2
p269 表9.5 ウェイトを求める手がかり
# マルチ・インデックス(初期使用) mult_index = pd.MultiIndex.from_tuples( [("学科", "優",'x1'), ("学科", "並",'x2') ,("面接","優",'y1'), ("面接", "並",'y2')] ,names=["Item", "Category",'Weight']) # マルチ・コラム(DF転置後に使用) mult_column = pd.MultiIndex.from_tuples( [("学科", "優",'x1'), ("学科", "並",'x2') ,("面接","優",'y1'), ("面接", "並",'y2'), ('作業用','',''),('実績d','','')] ,names=["Item", "Category",'Weight']) # 空のDFを作成 DF95b = pd.DataFrame( {'甲':['','','',''] ,'乙':['','','',''] ,'丙':['','','',''] ,'丁':['','','',''] ,'戊':['','','','']} ,index = mult_index) # 初期マルチ・インデックス DF95 = DF95b.T # 転置 # 学科の優・劣にレ点 for person in range(DF95.shape[0]): # 人数分繰り返し if DF94.iloc[person][0]=='優': # DF94 の情報をチェック DF95.iloc[person,(0,0)] = 'レ' # 学科の優にレ点 else: DF95.iloc[person,(1,1)] = 'レ' # 学科の並にレ点 # 面接の優・劣にレ点 for person in range(DF95.shape[0]): if DF94.iloc[person][1]=='優': DF95.iloc[person,(2,2)] = 'レ' # 面接の優にレ点 else: DF95.iloc[person,(3,3)] = 'レ' # 面接の並にレ点 # レ点セルについて、ウェイトを集計 DF95_bool = (DF95 == 'レ') # レ点判定の論理値取得 scores_list = [] for person in range(DF95.shape[0]): score = [] for score_col in range(DF95.shape[1]): cell = DF95_bool.iloc[person][score_col] if cell == True: # レ点あり(True判定)の場合 score.append(list(DF95.columns)[score_col][2]) #該当行のウェイトを加算 scores_list.append(score) # DFの仮組み bool93_col = pd.DataFrame([scores_list], columns =DF95.index[0:5]).T DF95 = pd.concat([DF95,bool93_col], axis=1) DF95 = pd.concat([DF95,DF94['入社後の実績']], axis=1) DF95.columns = mult_column # 転置後マルチ・コラム # 予測値e列DFの生成 explist = [] for item in range(DF95.shape[0]): equation = DF95['作業用'][item][0] +' + ' +DF95['作業用'][item][1]+' + c' # 数式表現化 explist.append(equation) expdata = pd.DataFrame(explist) mult_column2 = pd.MultiIndex.from_tuples( [('予測値e','計算式','')] ,names=["Item", "Category",'Weight']) # 予測値e 列用のコラム expdata.index = index_info expdata.columns = mult_column2 # DFの結合と整除 DF95 = pd.concat([DF95,expdata],axis=1) # 予測値e 列DFを結合 DF95.drop(DF95.columns[[4]], axis=1) # 作業用列を削除 DF95 = DF95.loc[:, ['学科','面接','予測値e', '実績d']] # 列の順序を整理 DF95
p271 数式の計算(DFから情報を取得)
import sympy as sy # シンボル文字を指定 x1 = sy.Symbol("x1",real=True) x2 = sy.Symbol("x2",real=True) y1 = sy.Symbol("y1",real=True) y2 = sy.Symbol("y2",real=True) c_value = str(DF95['実績d'].mean()) expected_list = [] for expected in range(5): c_update = DF95['予測値e']['計算式'][expected].replace('c', c_value) # cを平均値3に変更 expected_list.append(c_update) # 式9.2~式9.3 equ_93 = 0 for exp in range(len(expected_list)): seed = (DF95['実績d'][exp]- sy.sympify(expected_list[exp]))**2 # (実績-予測式)の2乗 equ_93 += seed.expand() # 展開計算 print(f'式9.3:') display(equ_93) # 式9.3
p271 数式の計算(式の展開、偏微分)
- 式の展開:Sympy の expand 機能を使用
- 式の微分:Sympy の diff 機能を使用
import sympy as sy # シンボル文字を指定 x1 = sy.Symbol("x1",real=True) x2 = sy.Symbol("x2",real=True) y1 = sy.Symbol("y1",real=True) y2 = sy.Symbol("y2",real=True) c = DF95['実績d'].mean() # DF95['予測値e'][計算式][0]~[4] e_Kou = x1 + y1 + c e_Otsu = x1 + y1 + c e_Hei = x1 + y2 + c e_Tei = x2 + y1 + c e_Bo = x2 + y1 + c expected_list = [e_Kou, e_Otsu, e_Hei, e_Tei, e_Bo] # 式9.2~式9.3 equ_93 = 0 for exp in range(len(expected_list)): seed = (DF95['実績d'][exp]- expected_list[exp])**2 # (実績-予測式)の2乗 equ_93 += seed.expand() # 展開計算 print(f'式9.3:') display(equ_93) # 式9.3 # 式9.4 print(f'\n式9.4:') for equ_94 in (x1, x2, y1, y2): display(equ_93.diff(equ_94)) # 式9.3 を各シンボル文字で偏微分
p271 数式の計算(連立方程式の解法)
- 連立方程式を行列形式の方程式にする。
- 変数の係数を取得:SymPy の coeff 機能を使用
- 方程式の解法:NumPy の solve 機能を利用
# 式9.5~9.6 from numpy.linalg import solve # 連立方程式を行列で解く ## 左辺の係数 left = [] # 行列方程式の左辺の係数を格納するリスト for diffs in equ_93_diffs: left_list = [] # 各微分方程式の係数を格納するリスト for variable in (x1,x2,y1,y2): left_list.append(float(diffs.coeff(variable))) # 各変数に対応する係数を抽出 left.append(left_list) ## 右辺の定数項 right = [] # 行列方程式の右辺(係数)を格納するリスト for diffs in equ_93_diffs: right.append(float(-diffs.coeff(x1,0).coeff(x2,0).coeff(y1,0).coeff(y2,0))) # 定数項を抽出 ## 解法を実行 answer = solve(left, right) # 文字数と解とをリスト化 answers_list = [] tick = 0 for equ_96 in (x1, x2, y1, y2): answers_list.append((equ_96,round(answer[tick],2))) tick +=1 # 結果を表示 for ans in range(len(answers_list)): print(answers_list[ans]) (x1, 0.0) (x2, -1.0) (y1, 1.0) (y2, -2.0)
p272~273 数式の計算(解の代入)
- 計算式に変数を代入して計算:NumPy の subs 機能を使用
substitution = answers_list # 代入リスト(文字数と解のリスト) expected_numbers = [] for expected in expected_list: # 予測値eの計算式 expected_numbers.append(expected.subs(substitution)) # 計算式に解を代入して計算 # 整数値リストに変換 DF_EN = [] for item in expected_numbers: DF_EN.append(float(item)) # DF化 en_DF = pd.DataFrame([DF_EN]).T en_DF.index = index_info mult_column3 = pd.MultiIndex.from_tuples( [('予測値e','数値','')] ,names=["Item", "Category",'Weight']) # 予測値e 列用のコラム en_DF.index = index_info en_DF.columns = mult_column3 # DFの結合と整除 DF95 = pd.concat([DF95, en_DF],axis=1) # 予測値eの計算式列DFを結合 DF95 = DF95.loc[:, ['学科','面接','予測値e', '実績d']] # 列の順序を整理 DF95
p273 基準が分類で与えられたら(数量化 Ⅱ 類)
外的判断基準が、数値ではなく、分類(例:合格/不合格)である場合に、因子(例:学科成績、面接成績)の加重度合いを求める。import pandas as pd import numpy as np allcolumns = ['','合否'] item =['学科','面接'] category = ['優','並'] weight = ['x1','x2','y1','y2'] person_list = ['ウェイト','甲','乙','丙','丁','戊','己'] result = [weight ,['レ','','レ',''] ,['レ','','','レ'] ,['レ','','','レ'] ,['','レ','レ',''] ,['','レ','レ',''] ,['','レ','','レ']] # 階層付きDF化 mult_column = pd.MultiIndex.from_product([item, category]) # 横軸の階層化 DF = pd.DataFrame(result, index =person_list, columns= mult_column) mult_column2 = pd.MultiIndex.from_product([['合否'], ['']]) result = pd.DataFrame(['','〇','〇','×','〇','×','×'], index =person_list, columns = mult_column2) DF = pd.concat([DF,result], axis=1) DF
p275 得点を因子のウェイトで数式表現する
# 演算対象をDF本体部分に限定 DFs = DF.iloc[1:len(person_list),0:len(category)*2] # レ点セルについて、ウェイトを集計し得点列を形成 DFs_bool = (DFs == 'レ') # レ点判定の論理値取得 scores_list = [''] for person in range(DFs.shape[0]): score = '' for score_col in range(DFs.shape[1]): cell = DFs_bool.iloc[person][score_col] if cell == True: # レ点あり(True判定)の場合 score += '+' + DF.iloc[0][score_col] #該当行のウェイト文字列を追記 score = score.lstrip('+') # 表記調整 scores_list.append(score) # 得点列を既存DFに統合 mult_column3 = pd.MultiIndex.from_product([['得点'], ['']]) scores_set = pd.DataFrame(scores_list, index =person_list, columns = mult_column3) DF2 = pd.concat([DF,scores_set], axis=1) DF2
p275 ウェイト付けの例
\(x_1=3\)
\(x_2=0\)
\(y_1=2\)
\(y_2=1\)
# ウェイトを代入後の数値に置換 DF_num = DF.replace({'x1':3, 'x2':0, 'y1':2, 'y2':1}) # 演算対象をDF本体部分に限定 DFsn = DF_num.iloc[1:len(person_list),0:len(category)*2] # DFsn = DF.iloc[1:len(person_list),0:len(category)*2] # レ点セルについて、ウェイトを集計し得点列を形成 DFsn_bool = (DFsn == 'レ') # レ点判定の論理値取得 # 得点を計算、集計、DF化 scores_list = [''] for person in range(DFsn.shape[0]): score = 0 for score_col in range(DFsn.shape[1]): cell = DFsn_bool.iloc[person][score_col] if cell == True: # レ点あり(True判定)の場合 score += DF_num.iloc[0][score_col] #該当行のウェイト文字列を追記 scores_list.append(score) # 得点列を既存DFに統合 mult_column3 = pd.MultiIndex.from_product([['得点'], ['']]) scores_set = pd.DataFrame(scores_list, index =person_list, columns = mult_column3) DF3 = pd.concat([DF_num,scores_set], axis=1) display(DF3) # 各グループの平均値 # 合格者 Passed = DF3[DF3['合否']=='〇'] # 合格者リスト Pass_m = Passed['得点'].mean() # 合格者の平均点数 print(f'合格者の平均点数:{round(Pass_m,2)}') # 不合格者 Failure = DF3[DF3['合否']=='×'] # 不格者リスト Failure_m =Failure['得点'].mean() # 不合格者の点数平均 print(f'不合格者の平均点数:{round(Failure_m,2)}') # 合格者平均と不合格者平均の2要素からなる集合の分散 PF_m_list = [Pass_m, Failure_m] # リスト化 import statistics var_2 = statistics.pvariance(PF_m_list) # 分散 print(f'合格者平均と不合格者平均の2要素からなる集合の分散:{round(var_2,2)}') # 全体の分散 var_all = statistics.pvariance(DF3['得点'][1:]) # 全体の分散 print(f'全体の分散:{var_all}') # 相関比 print(f'相関比:{round(var_2/var_all,2)}')
p275 相関比が最大となるようなウェイト付け ~相関比を数式化する~
(作業工程)
- 全体集合の分散を求める。
- 合格者平均と不合格者平均の2要素からなる集合の分散を求める。
- 相関比(1と2の比率)を数式化する。
- 相関比の極値ひいては最大値を求めるため、相関比をウェイト変数で偏微分する。
- 各偏微分の結果が0になるようなウェイト変数の値を求める。
import sympy as sy # シンボル文字を指定 x1 = sy.Symbol("x1",real=True) x2 = sy.Symbol("x2",real=True) y1 = sy.Symbol("y1",real=True) y2 = sy.Symbol("y2",real=True) u = sy.Symbol("u",real=True) v = sy.Symbol("v",real=True) KOU = x1 + y1 OTS = x1 + y2 HEI = x1 + y2 TEI = x2 + y1 BO = x2 + y1 KI = x2 + y2 all_list = [KOU, OTS, HEI, TEI, BO, KI] pass_list = [KOU, OTS, TEI] failure_list = [HEI, BO, KI] # 全平均 all_average = np.mean(all_list) print('全平均') display(all_average) # 全体の分散 numerator = 0 for element in all_list: numerator += (element - all_average)**2 denominator = len(all_list) all_variance = numerator/denominator print('\n全体の分散') display(all_variance) # vの式 v_num = (all_variance*12).expand() print('\n全体の分散 =v/12 と置くときの v') display(v_num) # 合格者平均と不合格者平均の2要素からなる集合の分散 # リスト化 list_pandf = [np.mean(pass_list), np.mean(failure_list)] # 分散 numerator_pandf = 0 for element_pf in list_pandf: numerator_pandf += (element_pf - all_average)**2 denominator_pf = len(list_pandf) pf_variance = numerator_pandf/denominator_pf print('\n合格者平均と不合格者平均の2要素からなる集合の分散') display(pf_variance) # uの式 u_num = (pf_variance*36).expand() print('\n合格者平均と不合格者平均の2要素からなる集合の分散 =u/36 と置くときの u') display(u_num) # 相関比 print('\n相関比') cr_uv_num = (u_num/v_num)/(36/12) cr_uv = cr_uv_num.subs({(v_num,v),(u_num,u)}) display(cr_uv)
p277 相関比が最大となるようなウェイト付け ~相関比の式の偏微分~
相関比
\(r = \cfrac {1} {3} \cfrac{u}{v}\)
が極値ひいては最大となるような \(x_1,x_2,y_1,y_2\) の条件を見つける。
→ 相関比を \(x_1,x_2,y_1,y_2\) で偏微分したうえで、それら4式が0となる条件を見つける。
→ 微分の商の公式:
\(\left (\dfrac {u} {v}\right)'=\dfrac {u'v-uv'} {v^2}\)
で、右辺の分子部分 \(u'v-uv'\)が0になる条件を見つける。
equ911_diffs = [] # 偏微分した各式の分子を格納するリスト equ_num = 1 for derivative in (x1,x2,y1,y2): # 各ウェイトで微分 rdx_nume = u_num.diff(derivative)*v - v_num.diff(derivative)*u # 分数関数の微分公式の分子 equ911_diffs.append(rdx_nume) print(f'({equ_num})式の左辺:') equ_num += 1 display(rdx_nume) print(f'\n')
p277 相関比が最大となるようなウェイト付け ~相関比微分式の因数分解~
上式(1)と(2)は同値(右辺は0であるためマイナスをかけると同じ)。→上式(1)のみを検討のため、因数分解。
上式(3)と(4)は同値(右辺は0であるためマイナスをかけると同じ)。→上式(3)のみを検討のため、因数分解。
- 因数分解:Sympy の factor 機能を使用
# (1)、(3)式に u, vを代入 subst_01 = equ911_diffs[0].subs({(v,v_num),(u,u_num)}).expand() subst_03 = equ911_diffs[2].subs({(v,v_num),(u,u_num)}).expand() # 因数分解 equ911f01 = sy.factor(subst_01) equ911f03 = sy.factor(subst_03) # 表示 print('(1)式:') display(equ911f01) print('\n') print('(3)式:') display(equ911f03)
因数分解をした(1)式 \(=0\) が成立するためには、
\(y_1-y_2=0\)
\(x_1-x_2-y_1+y_2=0\)
\(x_1-x_2+y_1-y_2=0\)
のいずれかが成立することが必要。
\(y_1\neq y_2\)
である。よって、上記3式のうち1番上の式は成立しない。このため、因数分解をした(1)式 \(=0\) が成立するためには、以下のいずれかが成立する必要がある。
\(x_1-x_2=y_1-y_2\neq0\)
\(x_1-x_2=-(y_1-y_2)\neq0\)
そして、本設例では、優秀 \(>\) 並みとなるように点数をつけるので、以下の不等式が成立する。
\(x_1>x_2\)
\(y_1>y_2\)
よって、上記2式のうち、下の式は成立しない(左辺がプラス、右辺がマイナスとなるため)。結局、本設例に合致する条件は、上記1式のみとなる。そして、上記1式は、以下の3式が共に成立することを意味する。
\(x_1-x_2=y_1-y_2\)
\(x_1\neq x_2\)
\(y_1\neq y_2\)
この条件は、式(3)の因数分解の左式を0とさせる(中項が0になる)。
p277 求めたウェイトを基に相関比を確認
# ウェイトを代入後の数値に置換 DF_num = DF.replace({'x1':1, 'x2':0, 'y1':1, 'y2':0}) # 演算対象をDF本体部分に限定 DFsn = DF_num.iloc[1:len(person_list),0:len(category)*2] # DFsn = DF.iloc[1:len(person_list),0:len(category)*2] # レ点セルについて、ウェイトを集計し得点列を形成 DFsn_bool = (DFsn == 'レ') # レ点判定の論理値取得 # 得点を計算、集計、DF化 scores_list = [''] for person in range(DFsn.shape[0]): score = 0 for score_col in range(DFsn.shape[1]): cell = DFsn_bool.iloc[person][score_col] if cell == True: # レ点あり(True判定)の場合 score += DF_num.iloc[0][score_col] #該当行のウェイト文字列を追記 scores_list.append(score) # 得点列を既存DFに統合 mult_column3 = pd.MultiIndex.from_product([['得点'], ['']]) scores_set = pd.DataFrame(scores_list, index =person_list, columns = mult_column3) DF3 = pd.concat([DF_num,scores_set], axis=1) display(DF3) # 各グループの平均値 # 合格者 Passed = DF3[DF3['合否']=='〇'] # 合格者リスト Pass_m = Passed['得点'].mean() # 合格者の平均点数 print(f'合格者の平均点数:{round(Pass_m,2)}') # 不合格者 Failure = DF3[DF3['合否']=='×'] # 不格者リスト Failure_m =Failure['得点'].mean() # 不合格者の点数平均 print(f'不合格者の平均点数:{round(Failure_m,2)}') # 合格者平均と不合格者平均の2要素からなる集合の分散 PF_m_list = [Pass_m, Failure_m] # リスト化 import statistics var_2 = statistics.pvariance(PF_m_list) # 分散 print(f'合格者平均と不合格者平均の2要素からなる集合の分散:{round(var_2,2)}') # 全体の分散 var_all = statistics.pvariance(DF3['得点'][1:]) # 全体の分散 print(f'全体の分散:{round(var_all,2)}') # 相関比 print(f'相関比:{round(var_2/var_all,2)}')
p278 基準がなくとも ~数量化 Ⅲ 類~ 表9.7
import pandas as pd person_list = ['A','B','C','D','E'] flower_list = ['Tulip','Morning glory','Horsetail','Rose'] DF = pd.DataFrame([['レ','','','レ'] ,['レ','','レ',''] ,['レ','レ','',''] ,['','','','レ'] ,['','レ','レ','']] ,index = person_list ,columns = flower_list)
p278 表9.7 行と列を配置換え
rea_DF = DF.reindex(index=['D','A','C','B','E'], columns=['Horsetail','Morning glory','Tulip','Rose']) rea_DF
p279 相関係数
num_DF = rea_DF.copy() num_DF.index = [4,3,2,1,0] num_DF.columns = range(num_DF.shape[1]) display(num_DF) x_list = [] y_list = [] for index in num_DF.index: # 行要素を繰返し for column in num_DF.columns: # 列要素を繰り返し if num_DF.loc[index][column] == 'レ': # レ点があるセル x_list.append(column) # コラム名を格納 y_list.append(index) # インデックス名を格納 x_series = pd.Series(x_list) y_series = pd.Series(y_list) print(f'\n相関係数:{round(x_series.corr(y_series),3)}') # 相関係数