Fisher(LDA)判別的推導+python代碼實現二分類

一、Fisher算法的主要思想

  • 線性判別分析(Linear Discriminant Analysis
    簡稱LDA)是一種經典的線性學習方法,在二分類問題上因爲最早由【Fisher,1936年】提出,所以也稱爲“Fisher 判別分析!”
    Fisher(費歇)判別思想是投影,使多維問題簡化爲一維問題來處理。選擇一個適當的投影軸,使所有的樣本點都投影到這個軸上得到一個投影值。對這個投影軸的方向的要求是:使每一類內的投影值所形成的類內離差儘可能小,而不同類間的投影值所形成的類間離差儘可能大。
    在這裏插入圖片描述

二、Fisher數學算法步驟

  • 爲了找到最佳投影方向,需要計算出 各類樣本均值、樣本類內離散度矩陣 Si\boldsymbol S_{i}S i和樣本總類內離散度矩陣 Sw\boldsymbolS_{w}Sw、樣本類間離散度矩陣 Sb\boldsymbol S_{b}Sb ,根據Fisher準則,找到最佳投影向量,將訓練集內的所有樣本進行投影,投影到一維Y空間,由於Y空間是一維的,則需要求出Y空間的劃分邊界點,找到邊界點後,就可以對待測樣本進行一維Y空間投影,判斷它的投影點與分界點的關係,將其歸類。具體方法如下(以兩類問題爲例子):

①計算各類樣本均值向量mim_i,mim_i是各個類的均值,NiN_iwiw_i類的樣本個數。

在這裏插入圖片描述

②計算樣本類內離散度矩陣SiS_i和總類內離散度矩陣SwS_w

在這裏插入圖片描述

③計算樣本類間離散度矩陣SbS_b

在這裏插入圖片描述

④求投影方向向量 WW (維度和樣本的維度相同)。我們希望投影后,在一維YY空間裏各類樣本儘可能分開,就是我們希望的兩類樣本均值之差(m1m2)(\overline{m_1}-\overline{m_2})越大越好,同時希望各類樣本內部儘量密集,即是:希望類內離散度越小越好。因此,我們可以定義Fisher準則函數爲:

在這裏插入圖片描述

2使得JF(w)J_F(w)取得最大值ww爲:

在這裏插入圖片描述

⑤將訓練集內所有樣本進行投影。

在這裏插入圖片描述

⑥. 計算在投影空間上的分割閾值y0y_0,在一維Y空間,各類樣本均值mi\overline{m_i}爲:

在這裏插入圖片描述
樣本類內離散度Si2\overline{S_i}^2和總類內離散度 Sw\overline{S_w}
在這裏插入圖片描述
而此時類間離散度就成爲兩類均值差的平方。
在這裏插入圖片描述

計算閾值y0y_0
在這裏插入圖片描述

⑦對於給定的測試樣本xx,計算出它在ww上的投影點yy

在這裏插入圖片描述

⑧根據決策規則分類!

在這裏插入圖片描述

三、python代碼實現

1.數據生成

from sklearn.datasets import make_multilabel_classification
import numpy as np

x, y = make_multilabel_classification(n_samples=20, n_features=2,
                                      n_labels=1, n_classes=1,
                                      random_state=2)  # 設置隨機數種子,保證每次產生相同的數據。

# 根據類別分個類
index1 = np.array([index for (index, value) in enumerate(y) if value == 0])  # 獲取類別1的indexs
index2 = np.array([index for (index, value) in enumerate(y) if value == 1])  # 獲取類別2的indexs

c_1 = x[index1]   # 類別1的所有數據(x1, x2) in X_1
c_2 = x[index2]   # 類別2的所有數據(x1, x2) in X_2

2、fisher算法實現

# 2、Fisher算法實現
def cal_cov_and_avg(samples):
    """
    給定一個類別的數據,計算協方差矩陣和平均向量
    :param samples:
    :return:
    """
    u1 = np.mean(samples, axis=0)
    cov_m = np.zeros((samples.shape[1], samples.shape[1]))
    for s in samples:
        t = s - u1
        cov_m += t*t.reshape(2, 1)
    return cov_m, u1
def fisher(c_1, c_2):
    """
    fisher算法實現(參考上面的推導公式進行理解)
    :param c_1:
    :param c_2:
    :return:
    """
    cov_1, u1 = cal_cov_and_avg(c_1)
    cov_2, u2 = cal_cov_and_avg(c_2)
    s_w = cov_1 + cov_2          # 總類內離散度矩陣。
    u, s, v = np.linalg.svd(s_w) # 下面的參考公式(4-10)
    s_w_inv = np.dot(np.dot(v.T, np.linalg.inv(np.diag(s))), u.T)
    return np.dot(s_w_inv, u1 - u2)

3、判斷類別

def judge(sample, w, c_1, c_2):
    """
    返回值:ture 屬於1;false 屬於2
    :param sample:
    :param w:
    :param c_1:
    :param c_2:
    :return:
    """
    u1 = np.mean(c_1, axis=0)
    u2 = np.mean(c_2, axis=0)
    center_1 = np.dot(w.T, u1) # 參考公式(2-8)
    center_2 = np.dot(w.T, u2)
    pos = np.dot(w.T, sample)  # 新樣本進來判斷
    return abs(pos - center_1) < abs(pos - center_2)

w = fisher(c_1, c_2)             # 調用函數,得到參數w
out = judge(c_2[1], w, c_1, c_2) # 判斷所屬的類別。
print(out)

4.繪圖

# 4、繪圖功能
plt.scatter(c_1[:, 0], c_1[:, 1], c='red')
plt.scatter(c_2[:, 0], c_2[:, 1], c='blue')
line_x = np.arange(min(np.min(c_1[:, 0]), np.min(c_2[:, 0])),
                   max(np.max(c_1[:, 0]), np.max(c_2[:, 0])),
                   step=1)
line_y = -(w[0]*line_x) / w[1]
plt.plot(line_x, line_y, linewidth=3.0,  label = 'fisher boundary line ')
plt.legend(loc='upper right')
plt.xlabel('feature 1')
plt.ylabel('feature 2')
plt.show()

5.運行結果:

在這裏插入圖片描述

參考鏈接:https://blog.csdn.net/abc13526222160/article/details/90611743
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章