LDA線性判別分析原理及python應用(葡萄酒案例分析)

目錄html

線性判別分析(LDA)數據降維及案例實戰

  1、LDA是什麼python

  2、計算散佈矩陣算法

  3、線性判別式及特徵選擇服務器

  4、樣本數據降維投影app

  5、完整代碼dom

  結語ide


 

1、LDA是什麼

  • LDA概念及與PCA區別

LDA線性判別分析(Linear Discriminant Analysis)也是一種特徵提取、數據壓縮技術。在模型訓練時候進行LDA數據處理能夠提升計算效率以及避免過擬合。它是一種有監督學習算法。學習

與PCA主成分分析(Principal Component Analysis)相比,LDA是有監督數據壓縮方法,而PCA是有監督數據壓縮及特徵提取方法。PCA目標是尋找數據集最大方差方向做爲主成分,LDA目標是尋找和優化具備可分性特徵子空間。其實二者各有優點,更深刻詳細的區分和應用等待以後的學習,這裏我仍然以葡萄酒數據集分類爲案例記錄原理知識的學習和具體實現步驟。優化

對比我以前記錄的PCA請看:PCA數據降維原理及python應用(葡萄酒案例分析)spa

  • LDA內部邏輯實現步驟
  1. 標準化d維數據集。
  2. 計算每一個類別的d維均值向量。
  3. 計算跨類散佈矩陣 \large S_{B} 和類內散佈矩陣 \large S_{W}.
  4. 線性判別式及特徵計算。
  5. 按特徵值降序排列,與對應的特徵向量成對排序。
  6. 選擇最具線性判別性的前k個特徵,構建變換矩陣\large W_{d\times k}.
  7. 經過變換矩陣將原數據投影至k維子空間。

2、計算散佈矩陣

一、數據集下載

下載葡萄酒數據集wine.data到本地,或者到時在加載數據代碼是從遠程服務器獲取,爲了不加載超時推薦下載本地數據集。

下載以後用記事本打開wine.data可見得,第一列爲葡萄酒數據類別標籤,共有3類,日後的13列爲特徵值。

數據加載以及標準化數據處理與PCA技術同樣,具體能夠翻看PCA數據降維原理及python應用(葡萄酒案例分析),或者本文第五部分完整代碼有具體實現代碼。

二、計算散佈矩陣第一步,先計算每一個類別每一個樣本的均值向量。

公式: \large m_{i}=\frac{1}{n_{i}}\sum_{x \in D}^{c}x_{m}, i =1,2,3 表示類別,每一個特徵取平均值。

獲得三個均值向量爲: \large m_{i}=\begin{bmatrix} \\ m_{i,1} \\ m_{i,2} \\ m_{i,3} \\ . \\ . \\ . \\ \\ m_{i,13} \end{bmatrix} 

代碼實現:

# 計算均值向量
np.set_printoptions(precision=4) mean_vecs = [] for label in range(1, 4): mean_vecs.append(np.mean(x_train_std[y_train == label], axis=0))

打印查看結果:

三、計算類內散佈矩陣。

每一個樣本 i 的散佈矩陣:

\large S_{i}=\sum_{x\in D}(x-m_i)(x-m_i)^{T}

類內散佈矩陣即每一個樣本的累加:

\large S_{W}=\sum_{i=1}^{13}S_i

代碼實現:

# 計算類內散佈矩陣
k = 13 Sw = np.zeros((k, k)) for label, mv in zip(range(1, 4), mean_vecs): Si = np.zeros((k, k)) Si = np.cov(x_train_std[y_train == label].T) Sw += Si print("類內散佈矩陣:",Sw.shape[0],"*",Sw.shape[1])

矩陣規模:

四、計算跨類散佈矩陣。

公式:\large S_{B}=\sum_{1}^{13}n_i(m_i-m)(m_i-m)^{T}

公式中,m是全部樣本總均值向量,也就是不分類的狀況下計算特徵平均值。

代碼實現:

# 計算跨類散佈矩陣
mean_all = np.mean(x_train_std, axis=0) Sb = np.zeros((k, k)) for i, col_mv in enumerate(mean_vecs): n = x_train[y_train == i + 1, :].shape[0] col_mv = col_mv.reshape(k, 1)  # 列均值向量
    mean_all = mean_all.reshape(k, 1) Sb += n * (col_mv - mean_all).dot((col_mv - mean_all).T)

3、線性判別式及特徵選擇

LDA其餘步驟與PCA類似,可是,PCA是分解協方差矩陣提取特徵值,LDA則是求解矩陣 \large S_{W}^{-1}S_B 獲得廣義特徵值,實現:

# 計算廣義特徵值
eigen_vals, eigen_vecs = np.linalg.eig(np.linalg.inv(Sw).dot(Sb)) eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i]) for i in range(len(eigen_vals))] eigen_pairs = sorted(eigen_pairs, key=lambda k: k[0], reverse=True)

對特徵值降序排列以後,打印看看:

print("特徵值降序排列:") for eigen_val in eigen_pairs: print(eigen_val[0])

從捕捉到的特徵值發現,前兩個能夠佔據大部分數據集特徵了,接下來可視化表示更加直觀地觀察:

# 線性判別捕捉,計算辨識力
tot = sum(eigen_vals.real) discr = [] # discr=[(i/tot) for i in sorted(eigen_vals.real,reverse=True)]
for i in sorted(eigen_vals.real, reverse=True): discr.append(i / tot) # print(discr)
cum_discr = np.cumsum(discr)  # 計算累加方差
plt.rcParams['font.sans-serif'] = ['SimHei']  # 顯示中文
plt.bar(range(1,14),discr,alpha=0.5,align='center',label='獨立辨識力') plt.step(range(1,14),cum_discr,where='mid',label='累加辨識力') plt.ylabel('"辨識力"比') plt.xlabel('線性判別') plt.ylim([-0.1,1.1]) plt.legend(loc='best') plt.show()

很明顯,最具線性判別的前兩個特徵捕捉了100%的信息,下面以此構建變換矩陣 W.

4、樣本數據降維投影

構建變換矩陣:

# 變換矩陣
w = np.hstack((eigen_pairs[0][1][:, np.newaxis].real, eigen_pairs[1][1][:, np.newaxis].real)) print(w)

來瞅瞅,這就是前兩個特徵向量的矩陣表示。

如今有了變換矩陣,就能夠將樣本訓練數據投影到降維特徵空間了:\large X^{'}=XW. 並展現分類結果:

# 樣本數據投影到低維空間
x_train_lda = x_train_std.dot(w) colors = ['r', 'g', 'b'] marks = ['s', 'x', 'o'] for l, c, m in zip(np.unique(y_train), colors, marks): plt.scatter(x_train_lda[y_train == l, 0], x_train_lda[y_train == l, 1] * -1, c=c, label=l, marker=m) plt.xlabel('LD 1') plt.ylabel('LD 2') plt.legend(loc='lower right') plt.show()

很明顯,三個類別線性可分,效果也不錯,相比較PCA方法,我感受LDA分類結果更好,咱們知道,LDA是有監督的方法,有利用到數據集的標籤。

5、完整代碼

 

import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split import matplotlib.pyplot as plt # load data
df_wine = pd.read_csv('D:\\PyCharm_Project\\maching_learning\\wine_data\\wine.data', header=None)  # 本地加載 # df_wine=pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data',header=None)#服務器加載
 
# split the data,train:test=7:3
x, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, stratify=y, random_state=0) # standardize the feature 標準化單位方差
sc = StandardScaler() x_train_std = sc.fit_transform(x_train) x_test_std = sc.fit_transform(x_test) # 計算均值向量
np.set_printoptions(precision=4) mean_vecs = [] for label in range(1, 4): mean_vecs.append(np.mean(x_train_std[y_train == label], axis=0)) # print("Mean Vectors %s:" % label,mean_vecs[label-1])
 
# 計算類內散佈矩陣
k = 13 Sw = np.zeros((k, k)) for label, mv in zip(range(1, 4), mean_vecs): Si = np.zeros((k, k)) # for row in x_train_std[y_train==label]:
    # row,mv=row.reshape(n,1),mv.reshape(n,1)
    # Si+=(row-mv).dot((row-mv).T)
    Si = np.cov(x_train_std[y_train == label].T) Sw += Si # print("類內散佈矩陣:",Sw.shape[0],"*",Sw.shape[1]) # print("類內標籤分佈:",np.bincount(y_train)[1:])
 
# 計算跨類散佈矩陣
mean_all = np.mean(x_train_std, axis=0) Sb = np.zeros((k, k)) for i, col_mv in enumerate(mean_vecs): n = x_train[y_train == i + 1, :].shape[0] col_mv = col_mv.reshape(k, 1)  # 列均值向量
    mean_all = mean_all.reshape(k, 1) Sb += n * (col_mv - mean_all).dot((col_mv - mean_all).T) # print("跨類散佈矩陣:", Sb.shape[0], "*", Sb.shape[1])
 
# 計算廣義特徵值
eigen_vals, eigen_vecs = np.linalg.eig(np.linalg.inv(Sw).dot(Sb)) eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i]) for i in range(len(eigen_vals))] eigen_pairs = sorted(eigen_pairs, key=lambda k: k[0], reverse=True) # print(eigen_pairs[0][1][:,np.newaxis].real) # 第一特徵向量 # print("特徵值降序排列:") # for eigen_val in eigen_pairs: # print(eigen_val[0])
 
# 線性判別捕捉,計算辨識力
tot = sum(eigen_vals.real) discr = [] # discr=[(i/tot) for i in sorted(eigen_vals.real,reverse=True)]
for i in sorted(eigen_vals.real, reverse=True): discr.append(i / tot) # print(discr)
cum_discr = np.cumsum(discr)  # 計算累加方差 # plt.rcParams['font.sans-serif'] = ['SimHei'] # 顯示中文 # plt.bar(range(1,14),discr,alpha=0.5,align='center',label='獨立辨識力') # plt.step(range(1,14),cum_discr,where='mid',label='累加辨識力') # plt.ylabel('"辨識力"比') # plt.xlabel('線性判別') # plt.ylim([-0.1,1.1]) # plt.legend(loc='best') # plt.show()
 
# 轉換矩陣
w = np.hstack((eigen_pairs[0][1][:, np.newaxis].real, eigen_pairs[1][1][:, np.newaxis].real)) # print(w)
 
# 樣本數據投影到低維空間
x_train_lda = x_train_std.dot(w) colors = ['r', 'g', 'b'] marks = ['s', 'x', 'o'] for l, c, m in zip(np.unique(y_train), colors, marks): plt.scatter(x_train_lda[y_train == l, 0], x_train_lda[y_train == l, 1] * -1, c=c, label=l, marker=m) plt.xlabel('LD 1') plt.ylabel('LD 2') plt.legend(loc='lower right') plt.show()
View Code

 

結語

這篇記錄了這幾天學習的LDA實現數據降維的方法,仍然以葡萄酒數據集爲案例,在上面一步步的拆分中,咱們更加清楚線性判別分析LDA方法的內部實現,在這個過程,對於初步學習的我感受可以認識和理解更深入,固然之後數據處理使用LDA方法時候會用到一些第三方庫的類,實現起來更加方便,加油學習,期待下一篇LDA實現更簡潔的方法!


個人博客園:http://www.javashuo.com/article/p-zmokooit-kb.html

個人CSDN博客:原創 LDA數據壓縮原理及python應用(葡萄酒案例分析)


 

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接:https://blog.csdn.net/Charzous/article/details/108007441
相關文章
相關標籤/搜索