スタートページJavaScript他言語Python 目次>    ←主成分分析  →クラスター分析

判別分析(フィッシャーの判別関数)

下記の青線の部分をGoogle Colaboratryの「コード」部分にコピーアンドペースト(ペーストは Cntl+V)して実行すれば、右図の画像が表示されます。


          )

判別分析とは

特性 c0,c1,c2,… をもつ多数のデータ群 A,B,C,… を、あらかじめグループ群(正群、負群)に区分しておき、それに統計的処理をするとにより、
    Z = b0*c0 + b1*c1 + b2*c2 +…
の b0.b1.b2,… を決定します。
そして、新データが与えられたとき、Zを計算して、Z>0ならば正群、Z<0ならば負群に属しると判別します。
このような統計的方法を判別分析といい、Zを判別関数といいます。判別関数を算出する方法はいくつかありますが、代表的なものにフィッシャーの判別関数があります。

実行例

ここでは、各行に判別値(group)として1と-1を与え、c0~c5 の値から判別関数Zを作成します。 numpy.linalg や sklearn などのライブラリが用いれれていますが、その説明は「主成分分析」(pca.txt) を参照してください。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# ================================ 入力データ
df = pd.DataFrame([
                   ['A',-1, 3, 4, 4, 5, 4, 4],
                   ['B',-1, 6, 6, 7, 8, 7, 7],
                   ['C', 1, 6, 5, 7, 5, 5, 6],
                   ['D',-1, 6, 7, 5, 4, 6, 5],
                   ['E', 1, 5, 7, 6, 5, 5, 5],
                   ['F',-1, 4, 5, 5, 5, 6, 6],
                   ['G', 1, 6, 6, 7, 6, 4, 4],
                   ['H',-1, 5, 5, 4, 5, 5, 6],
                   ['I', 1, 6, 6, 6, 7, 7, 6],
                   ['J', 1, 6, 5, 6, 6, 5, 5],
                   ['K',-1, 5, 4, 4, 5, 5, 5],
                   ['L', 1, 5, 5, 6, 5, 4, 5],
                   ['M', 1, 6, 6, 5, 5, 6, 5],
                   ['N', 1, 5, 5, 4, 4, 5, 3],
                   ['O',-1, 5, 6, 4, 5, 6, 6],
                   ['P', 1, 6, 6, 6, 4, 4, 5],
                   ['Q',-1, 4, 4, 3, 6, 5, 6],
                   ['R', 1, 6, 6, 7, 4, 5, 5],
                   ['S',-1, 5, 3, 4, 3, 5, 4],
                   ['T', 1, 4, 6, 6, 3, 5, 4]],
                 columns = ['name','group','c0','c1','c2','c3','c4','c5'])
# =========== グループ別の行列に変換
#   group の正負により、正群x1と負群x2に分割、計算に用いる列だけを取り込み
#   ndarray に変換
x = df[['c0','c1','c2','c3','c4','c5']].values
x1 =  df[df.group > 0].loc[:,['c0','c1','c2','c3','c4','c5']].to_numpy()   # 正群
x2 =  df[df.group < 0].loc[:,['c0','c1','c2','c3','c4','c5']].to_numpy()   # 負群
# ===========  諸元の算出
n1 = len(x1)                 # x1 の要素数
n2 = len(x2)                 #
m1 = np.mean(x1, axis=0)     # x1 の平均
m2 = np.mean(x2, axis=0)     #           
m = (m1*n1+m2*n1)/(n1+n2)    # 全体の平均
#
# ========================= 判別関数の計算
#
import numpy.linalg as LA
sw = ((x1-m1).T @ (x1-m1)) + ((x2-m2).T @ (x2-m2)) 
sinv = np.linalg.inv(sw)
w = -sinv @ (m2 - m1)
print('重み:w = ', w)
print('平均:m = ', m)
print('判別関数:Z = w[0]*(c0-m[0]) + w[1]*(c1-m[1]) + w[2]*(c2-m[2]) + …;  >0なら正群 <0なら負群')
# ============= 元配列に判別関数をあてはめる
df['Z'] = np.dot(x-m, w)
df['err'] = ' '
df.loc[(df.group * df.Z < 0), 'err'] = '×'
print(df)
# ============= 判別関数の算出としてはこれまでです
#        以降は図の作成のためです。
#
# 主成分分析
from sklearn.decomposition import FactorAnalysis as FA
corr = df.corr()                     #  共分散行列
eig, eigv = np.linalg.eig(corr)      # eig 固有値
fa = FA(n_components=2, max_iter=500)
fa.fit(x)
df['f1'] = fa.fit_transform(x)[:,0]  # 第1因子の値
df['f2'] = fa.fit_transform(x)[:,1]  # 第2因子の値
# 散布図作成
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
df.loc[df['group'] > 0, 'color'] = 'b'
df.loc[df['group'] < 0, 'color'] = 'r'
ax.scatter(df.f1, df.f2, color=df.color)
for i, txt in enumerate(df.name):
    ax.annotate(txt, (df.f1[i], df.f2[i]), size=14)
ax.grid()
ax.plot([-3,3],[0,0], color='k', linewidth=1)
ax.plot([0,0],[-2,2.5], color='k', linewidth=1)
fig.show()

結果と説明

判別関数の決定
  重み:w =  [ 0.060  0.045  0.102 0.015 -0.050 -0.118 ]
  平均:m =  [ 5.677  5.838  5.744 5.511  5.744  5.644 ]

  判別関数:Z = w[0]*(c0-m[0]) + w[1]*(c1-m[1]) + w[2]*(c2-m[2]) + …;
       >0なら正群 <0なら負群

元データへの当てはめ
        name  group  c0   c1   c2   c3   c4   c5       Z     err
     0    A    -1     3    4    4    5    4    4    -0.146
     1    B    -1     6    6    7    8    7    7    -0.031
     2    C     1     6    5    7    5    5    6     0.097
     3    D    -1     6    7    5    4    6    5     0.036    ×
     4    E     1     5    7    6    5    5    5     0.144
     5    F    -1     4    5    5    5    6    6    -0.277
     6    G     1     6    6    7    6    4    4     0.445
     7    H    -1     5    5    4    5    5    6    -0.269
     8    I     1     6    6    6    7    7    6    -0.030    ×
     9    J     1     6    5    6    6    5    5     0.129
    10    K    -1     5    4    4    5    5    5    -0.195
    11    L     1     5    5    6    5    4    5     0.104
    12    M     1     6    6    5    5    6    5     0.006
    13    N     1     5    5    4    4    5    3     0.071
    14    O    -1     5    6    4    5    6    6    -0.274
    15    P     1     6    6    6    4    4    5     0.194
    16    Q    -1     4    4    3    6    5    6    -0.461
    17    R     1     6    6    7    4    5    5     0.246
    18    S    -1     5    3    4    3    5    4    -0.152
    19    T     1     4    6    6    3    5    4     0.127

・group と Z が異なる符号ならば、元データがこの判別関数に合致しなかったことを示します。
 20件中、合致しなかったのはDとIの2件なので、この判別関数は適切だといえます。
・Zの絶対値が大ならば、明らかにその群に属するといえます。
 0に近いものは、「どちらかといえばその群になるが、他の群である可能性は否定できない」といえます。
・この関係を可視化するとグラフになります。