機械学習---LDAコード

1. 投影座標を取得する

import numpy as np


def GetProjectivePoint_2D(point, line):
    a = point[0]
    b = point[1]
    k = line[0]
    t = line[1]

    if   k == 0:      return [a, t]
    elif k == np.inf: return [0, b]
    x = (a+k*b-k*t) / (k*k+1)
    y = k*x + t
    return [x, y]

       この関数は、点から直線への投影点の座標を取得するために使用されます。関数のパラメータ point は、[a, b] で表される点の座標を表します。

パラメータ ラインは [k, t] の形式で表現される直線のパラメータを表し、k は直線の傾きを表し、t は直線の切片を表します。

距離。関数の戻り値は、[a',b'] の形式で表される投影点の座標です。

関数の具体的な実装は次のとおりです。

pointパラメータから点の横座標aと縦座標bを取得し、lineパラメータから直線の傾きkと切片tを取得します。

傾き k が 0 の場合、直線は水平線、投影点の縦軸は直線の切片 t、横軸は変更されず、投影点の座標が返されます。

[で]。

傾き k が正の無限大の場合、直線は垂直線、投影点の横座標は 0、縦座標は変化せず、投影点の座標が返されます。

[0,b]。

投影点の横座標 x を計算します。式は x = (a + k b - k t) / (k*k + 1) です。

直線 y = k*x + t の方程式を使用して、投影された点の縦座標 y を計算します。

投影点の座標 [x, y] を返します。

注: この関数は、numpy ライブラリの inf を使用して正の無限大を表します。

2. 散布図を描く

X = dataset[:,1:3]
y = dataset[:,3]
print(X,y)
# draw scatter diagram to show the raw data
f1 = plt.figure(1)       
plt.title('watermelon_3a')  
plt.xlabel('density')  
plt.ylabel('ratio_sugar')  
print(X[y == 0,0], X[y == 0,1])
plt.scatter(X[y == 0,0], X[y == 0,1], marker = 'o', color = 'k', s=100, label = 'bad')
plt.scatter(X[y == 1,0], X[y == 1,1], marker = 'o', color = 'g', s=100, label = 'good')
plt.legend(loc = 'upper right')  
plt.show()

Python では、ブールインデックス操作を配列オブジェクトに直接適用できます。

       これを実行すると、各要素が配列内の対応する位置の値となるy == 0ブール配列が生成されます。y

結果がない場合は 0 になります。たとえば、y配列の要素が 1 の場合、対応するブール配列要素は False になりますy

要素が 0 の場合、対応するブール配列要素は True になります。このブール配列を別のインデックスとして使用できます。

配列を使用して条件を満たす要素を取得します。2 次元配列の場合、最初のインデックスは行を表し、2 番目のインデックスは行を表します。

リスト。したがって、配列の対応する位置の値が 0 に等しい、行インデックスの列 0 の要素をX[y == 0, 0]取得することを意味します。Xy

白。

3. LDA 分類

from sklearn import model_selection
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn import metrics
import matplotlib.pyplot as plt

# generalization of train and test set
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.5, random_state=0)

# model fitting
lda_model = LinearDiscriminantAnalysis(solver='lsqr', shrinkage=None).fit(X_train, y_train)

# model validation
y_pred = lda_model.predict(X_test)

# summarize the fit of the model
print(metrics.confusion_matrix(y_test, y_pred))
print(metrics.classification_report(y_test, y_pred))

# draw the classfier decision boundary
f2 = plt.figure(2) 
h = 0.001
# x0_min, x0_max = X[:, 0].min()-0.1, X[:, 0].max()+0.1
# x1_min, x1_max = X[:, 1].min()-0.1, X[:, 1].max()+0.1

x0, x1 = np.meshgrid(np.arange(-1, 1, h),
                     np.arange(-1, 1, h))

# x0, x1 = np.meshgrid(np.arange(x0_min, x0_max, h),
#                      np.arange(x1_min, x1_max, h))

z = lda_model.predict(np.c_[x0.ravel(), x1.ravel()]) 

# Put the result into a color plot
z = z.reshape(x0.shape)
plt.contourf(x0, x1, z)

# Plot also the training pointsplt.title('watermelon_3a')  
plt.title('watermelon_3a')  
plt.xlabel('density')  
plt.ylabel('ratio_sugar')  
plt.scatter(X[y == 0,0], X[y == 0,1], marker = 'o', color = 'k', s=100, label = 'bad')
plt.scatter(X[y == 1,0], X[y == 1,1], marker = 'o', color = 'g', s=100, label = 'good')
plt.show()

        model_selection モジュールの train_test_split 関数。この関数の機能は、データセットをトレーニングセットとテストセットに分割することです。

分割データを設定して返します。

具体的には、train_test_split 関数のパラメータには次のものが含まれます。

X: 分割する特徴データセット

y: 分割するターゲット変数データセット

test_size: テスト セットのサイズ。浮動小数点数 (比率を表す) または整数 (サンプル数を表す) にすることができます。

random_state: パーティショニングのランダム性を制御するために使用されるランダム シード

関数の戻り値は 4 つの配列です。

X_train: トレーニングセットの特徴データ

X_test: テストセットの特徴データ

y_train: トレーニングセットのターゲット変数データ

y_test: テストセット内のターゲット変数の数

       LinearDiscriminantAnalysis クラスのいくつかの一般的なパラメーターとその意味:

ソルバー: LDA モデルのパラメーターを計算するために使用されるソルバーの選択。オプションのソルバーには以下が含まれます: 'svd': 特異値分解

(特異値分解)、あらゆる次元のデータに適しています。'lsqr': 最小二乗法 (最小

正方形)、高次元データに適しています。'eigen': サンプルに適した固有値分解

このデータ。

収縮: LDA モデルの収縮の程度を制御するために使用される収縮パラメーターの選択。オプションの収縮パラメータは次のとおりです。 なし: すべきではありません。

収縮の場合は、従来の LDA メソッドを使用します。'auto': 収縮パラメーターを自動的に選択し、データの特性に基づいて収縮の程度を自動的に決定します。

浮動小数点数: 収縮パラメータの値を手動で指定します。値が大きいほど、収縮の度合いが高くなります。

n_components: 次元削減後のフィーチャの次元数。デフォルト値は None です。これは、次元削減が実行されないことを意味します。

事前確率: カテゴリの事前確率。事前確率が指定されている場合、LDA モデルはこれらの事前確率を使用して計算されます。

store_covariance: カテゴリの共分散行列を保存するかどうか。デフォルトは False で、共分散行列が保存されないことを意味します。設定されている場合

True の場合、カテゴリの共分散行列には covariance_ 属性を通じてアクセスできます。

       lda_model.predict(X_test) の機能は、すでにトレーニングされた LDA モデル lda_model を使用してテスト セット データをテストすることです。

X_test は予測を行い、予測されたターゲット変数の値を返します。

       metrics.confusion_matrix(y_test, y_pred) の機能は、予測結果と実際のラベルの間の混同行列を計算することです。

この関数のパラメータには次のものが含まれます。 y_test: テスト セットの真のラベル。1 次元の配列またはリストです。y_pred: モデル ペア テスト セット

予測結果も 1 次元の配列またはリストになります。

        metrics.classification_report(y_test, y_pred) の機能は、分類モデルの分類レポートを生成することです。

一部の評価メトリクスは、テスト セットでのモデルのパフォーマンスを評価するために使用されます。分類レポートは次の指標を提供します。 精度

(精度): 陽性であると予測されたサンプルのうち、実際に陽性であるサンプルの割合。思い出してください: サンプルは実際にはポジティブな例です

、正しく予測された陽性例の割合。F1スコア(F1-Score):適合率と再現率を総合的に考慮した指標。

の調和平均 サポート: 各カテゴリのテスト セット内のサンプルの数。

       np.arange(-1, 1, h): 1 次元配列を生成するための開始値、終了値、ステップ サイズを指定します。ここで、開始値は -1 で、終了値は -1 です。

ビーム値は 1、ステップ サイズは h です。np.meshgrid 関数の機能は、これら 2 つの 1 次元配列を 2 つの 2 次元配列 x0 と x1 に変換することです。

ここで、x0 の各行は np.arange(-1, 1, h)、x1 の各列は np.arange(-1, 1, h) です。

       np.ravel(arr) には、元の配列内のすべての要素が左から右、上から下に配置されています。np.c_

[x0.ravel(), x1.ravel()] 2 つの 2 次元配列 x0 と x1 をフラット化し、それらを列ごとに連結して新しい 2 次元配列を作成します。この方法で入手してください

配列は、2 次元グリッド内のすべての点の座標を表します。

       このような予測を行う目的は、分類器の決定境界を視覚化することです。2 次元グリッド内に一連の座標点を生成し、

これらの点を予測することで、各点の予測カテゴリを取得できます。これらの予測を使用して、決定の境界線を引くことができます。決める

ポリシー境界は、分類子が特徴空間内の異なるクラスを分離する境界です。決定境界をプロットすることで分類器を視覚的に理解できます

さまざまな地域の分類結果。

       2 次元グリッド内の点を予測することにより、各点の予測カテゴリ z が取得されます。次に、plt.contourf() 関数を使用します。

これらの予測をカラー マップにプロットします。異なる色は異なるカテゴリを表します。

4. パラメータwを計算する

u = []  
for i in range(2): # two class
    u.append(np.mean(X[y==i], axis=0))  # column mean

# 2-nd. computing the within-class scatter matrix, refer on book (3.33)
m,n = np.shape(X)
Sw = np.zeros((n,n))
for i in range(m):
    x_tmp = X[i].reshape(n,1)  # row -> cloumn vector
    if y[i] == 0: u_tmp = u[0].reshape(n,1)
    if y[i] == 1: u_tmp = u[1].reshape(n,1)
    Sw += np.dot( x_tmp - u_tmp, (x_tmp - u_tmp).T )

Sw = np.mat(Sw)
U, sigma, V= np.linalg.svd(Sw) 

Sw_inv = V.T * np.linalg.inv(np.diag(sigma)) * U.T
# 3-th. computing the parameter w, refer on book (3.39)
w = np.dot( Sw_inv, (u[0] - u[1]).reshape(n,1) )  # here we use a**-1 to get the inverse of a ndarray

print(w)

このコードは、線形判別分析でパラメーター w を計算するために使用されます。以下はコードです

説明する:

まず、各カテゴリの平均ベクトルを格納する空のリスト u を作成します。

次に、各カテゴリをループすることによって、各カテゴリの平均ベクトルが計算され、リスト u に追加されます。

次に、クラス内散布行列を計算します。まず、全ゼロ行列 Sw を初期化します。

は (n,n) です。n は特徴ベクトルの次元です。次に、各サンプルをループしてサンプル ベクトルを列ベクトルに転置します。

そして、それが属するカテゴリに従って、対応する平均ベクトルを選択します。次に、各サンプル ベクトルとそのカテゴリの平均ベクトルの差を計算します。

、その転置を乗算し、最後に結果を Sw に累積します。

Swを行列型に変換します。

Sw に対して特異値分解 (SVD) を実行して、行列 U、シグマ、および V を取得します。

Sw の逆行列 Sw_inv を計算します。ここで、VT は V の転置を表し、np.linalg.inv(np.diag(sigma)) はシグマの逆行列を表します。

対角行列。

最後に、カテゴリ 0 の平均ベクトル u[0] とカテゴリ 1 の平均ベクトル u[1] の差を Sw_inv に乗じて、パラメータ w を計算します。

到着。**-1 は、ndarray の逆行列を取得するためにここで使用されます。

5. 2 次元散布図と LDA 結果を描画する

f3 = plt.figure(3)
plt.xlim( -0.2, 1 )
plt.ylim( -0.5, 0.7 )

p0_x0 = -X[:, 0].max()
p0_x1 = ( w[1,0] / w[0,0] ) * p0_x0
p1_x0 = X[:, 0].max()
p1_x1 = ( w[1,0] / w[0,0] ) * p1_x0

plt.title('watermelon_3a - LDA')  
plt.xlabel('density')  
plt.ylabel('ratio_sugar')  
plt.scatter(X[y == 0,0], X[y == 0,1], marker = 'o', color = 'k', s=10, label = 'bad')
plt.scatter(X[y == 1,0], X[y == 1,1], marker = 'o', color = 'g', s=10, label = 'good')
plt.legend(loc = 'upper right')  

plt.plot([p0_x0, p1_x0], [p0_x1, p1_x1])

# draw projective point on the line


m,n = np.shape(X)
for i in range(m):
    x_p = GetProjectivePoint_2D( [X[i,0], X[i,1]], [w[1,0] / w[0,0] , 0] ) 
    if y[i] == 0: 
        plt.plot(x_p[0], x_p[1], 'ko', markersize = 5)
    if y[i] == 1: 
        plt.plot(x_p[0], x_p[1], 'go', markersize = 5)   
    plt.plot([ x_p[0], X[i,0]], [x_p[1], X[i,1] ], 'c--', linewidth = 0.3)

plt.show()

f3 という名前のグラフィックス オブジェクトを作成します。X軸の表示範囲を-0.2~1の範囲で設定します。Y軸の表示範囲を-0.5~0.7に設定します。

カテゴリ 0 の最初の次元フィーチャの最大値の逆数を計算します。重みに基づいてカテゴリ 0 の 2 番目の次元フィーチャの値を計算します。

カテゴリ 1 の最初の寸法フィーチャの最大値を計算します。重みに基づいてカテゴリ 1 の 2 番目の次元フィーチャの値を計算します。

        p0_x0 は X 軸の最小値を表し、p0_x1 は線形モデルによって計算された p0_x0 に対応する予測値を表します。同じ

プロットにおいて、p1_x0 は X 軸の最大値を表し、p1_x1 は線形モデルによって計算された p1_x0 に対応する予測値を表します。

この目的は、線形モデルのパフォーマンスを 2 次元で視覚化することです。これら 2 つの点を計算すると、次のようになります。

上に直線が引かれます。これは線形モデルの決定境界を表します。これにより、入力データの線形モデル分析をより深く理解できるようになります。

クラスまたは回帰機能。

グラフのタイトルを「watermelon_3a - LDA」に設定します。X 軸のラベルを「密度」に設定します。

y 軸のラベルを「ratio_sugar」に設定します。カテゴリ 0 の散布図を黒点で表し、サイズ 10、ラベルをプロットします。

悪い'。サイズ 10 の緑色の点で表され、「良好」というラベルが付けられたカテゴリ 1 の散布図を描画します。

グラフの右上隅に凡例を表示します。カテゴリ 0 とカテゴリ 1 の投影点を結ぶ直線を描きます。

データセット X の形状を取得します。m はサンプル数、n は特徴の数です。各サンプルを反復処理します。

        x_p = GetProjectivePoint_2D([X[i, 0], X[i, 1]], [w[1, 0] / w[0, 0], 0]): 直線上のサンプル点の投影を計算します。

シャドウポイント。関数 GetProjectivePoint_2D には 2 つのパラメータがあります: [X[i, 0], X[i, 1]]: これは 2 つの要素を含む列です

テーブルは 2 次元平面上の点の座標を表します。X[i, 0] は点の x 座標を表し、X[i, 1] は点の y 座標を表します。[w[1, 0] /

w[0, 0], 0]: これは、ベクトルの座標を表す 2 つの要素のリストです。w[1, 0] / w[0, 0] はベクトルの x を表します

コンポーネントの場合、0 はベクトルの y コンポーネントを表します。この関数の機能は、指定された 2 次元平面上の点 [X[i, 0], X[i, 1]] をベクトルに投影することです。

[w[1, 0] / w[0, 0], 0] と投影点の座標を返します。

        サンプルがカテゴリ 0 に属する場合。サイズ 5 の黒い点で表されるカテゴリ 0 の投影点を描画します。サンプルがカテゴリに属する​​場合

1. サイズ 5 の緑色の点で表されるカテゴリ 1 の投影点を描画します。シアンを使用して、サンプル点から投影点まで破線を描きます。

破線は線幅が 0.3 であることを示します。

6. LDA の例

X = np.delete(X, 14, 0)
y = np.delete(y, 14, 0)

u = []  
for i in range(2): # two class
    u.append(np.mean(X[y==i], axis=0))  # column mean

# 2-nd. computing the within-class scatter matrix, refer on book (3.33)
m,n = np.shape(X)
Sw = np.zeros((n,n))
for i in range(m):
    x_tmp = X[i].reshape(n,1)  # row -> cloumn vector
    if y[i] == 0: u_tmp = u[0].reshape(n,1)
    if y[i] == 1: u_tmp = u[1].reshape(n,1)
    Sw += np.dot( x_tmp - u_tmp, (x_tmp - u_tmp).T )

Sw = np.mat(Sw)
U, sigma, V= np.linalg.svd(Sw) 

Sw_inv = V.T * np.linalg.inv(np.diag(sigma)) * U.T
# 3-th. computing the parameter w, refer on book (3.39)
w = np.dot( Sw_inv, (u[0] - u[1]).reshape(n,1) )  # here we use a**-1 to get the inverse of a ndarray

print(w)

# 4-th draw the LDA line in scatter figure

# f2 = plt.figure(2)
f4 = plt.figure(4)
plt.xlim( -0.2, 1 )
plt.ylim( -0.5, 0.7 )

p0_x0 = -X[:, 0].max()
p0_x1 = ( w[1,0] / w[0,0] ) * p0_x0
p1_x0 = X[:, 0].max()
p1_x1 = ( w[1,0] / w[0,0] ) * p1_x0

plt.title('watermelon_3a - LDA')  
plt.xlabel('density')  
plt.ylabel('ratio_sugar')  
plt.scatter(X[y == 0,0], X[y == 0,1], marker = 'o', color = 'k', s=10, label = 'bad')
plt.scatter(X[y == 1,0], X[y == 1,1], marker = 'o', color = 'g', s=10, label = 'good')
plt.legend(loc = 'upper right')  

plt.plot([p0_x0, p1_x0], [p0_x1, p1_x1])

# draw projective point on the line


m,n = np.shape(X)
for i in range(m):
    x_p = GetProjectivePoint_2D( [X[i,0], X[i,1]], [w[1,0] / w[0,0] , 0] ) 
    if y[i] == 0: 
        plt.plot(x_p[0], x_p[1], 'ko', markersize = 5)
    if y[i] == 1: 
        plt.plot(x_p[0], x_p[1], 'go', markersize = 5)   
    plt.plot([ x_p[0], X[i,0]], [x_p[1], X[i,1] ], 'c--', linewidth = 0.3)

plt.show()

このコードは、分類問題に対する線形判別分析 (LDA) アルゴリズムを実装します。具体的な手順は次のとおりです。

データセット X から行 14 を削除し、y というラベルを付けて、2 クラス分類の準備をします。

2 種類のデータの平均ベクトル u を計算します。u[0] は 1 番目のタイプのデータの平均ベクトルを表し、u[1] は 2 番目のタイプのデータの平均ベクトルを表します。

クラス内分散行列 Sw、つまり各カテゴリ内のサンプルの分散度を計算します。Sw を解くために一般化逆および特異値分解 (SVD) が使用されます

の逆行列。

識別方向ベクトルであるパラメータ w を計算します。w は、Sw の逆行列と u[0] と u[1] の差の積を使用して計算されます。

散布図を描き、LDA ラインを描くと、パラメーター w に従ってラインの傾きが計算されます。

LDA ライン上にサンプル点の投影点を描画します。

最後にグラフを表示します。

 

 

 

 

 

 

 

 

 

 

 

 

 

おすすめ

転載: blog.csdn.net/weixin_43961909/article/details/132512157