貝葉斯分類小結
在《貝葉斯之樸素理解》比較詳細地總結了一個樸素貝葉斯。這裡再對非樸素貝葉斯做一個小結,以了結貝葉斯分類。
1、非樸素貝葉斯公式
1.1 高維高斯分佈
在此之前,我們同樣先需準備一些數學知識,高維高斯概率分佈 ,或者也叫做聯合高斯概率分佈,它有如下公式
\[ p(\mathbf{x})=\frac{1}{\sqrt{(2\pi)^n|\Sigma|}}\exp\left(-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})\Sigma^{-1}(\mathbf{x}-\boldsymbol{\mu})^T\right) \tag{1-1} \]
注:如果特徵屬性是以列向量 的形式表示的,那麼上式(1-1)應表示為
\[ p(\mathbf{x})=\frac{1}{\sqrt{(2\pi)^n|\Sigma|}}\exp\left(-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^T\Sigma^{-1}(\mathbf{x}-\boldsymbol{\mu})\right) \]
上式中,\(\boldsymbol{\mu}=(\mu_1,\mu_2,\cdots,\mu_n)\) 表示特徵\(\mathbf{x}=(x_1,x_2,\cdots,x_n)\) 的均值向量,即有
\[ \mu_i = \frac{1}{m}\sum_{j=1}^{m}x_{ij},\ i = 1,2,\cdots,n;\ j=1,2,\cdots,m \tag{1-2} \]
注:其中\(n\) 表示特徵的個數,\(m\) 表示樣本數 。
\(\Sigma\) 表示協方差矩陣,\(|\Sigma|\) 表示協方差矩陣的行列式,協方差陣可以表示為
\[ \Sigma=\frac{1}{m}\sum_{i=1}^{m}(\mathbf{x}_j-\boldsymbol{\mu})^T(\mathbf{x}_j-\boldsymbol{\mu}) \tag{1-3} \]
其中\(\mathbf{x}_j\)表示第
\(j\)
個樣本的特徵行向量。
1.2 聯合貝葉斯公式
與ofollow,noindex" target="_blank">《貝葉斯之樸素理解》第2小節 中的貝葉斯公式類似,可以表達為如下公式
\[ p(c_k|\mathbf{x})=\frac{p(\mathbf{x}|c_k)p(c_k)}{p(\mathbf{x})} \tag{1-4} \]
同樣我們可以假設其中的似然概率 \(p(\mathbf{x}|c_k)\) 服從高斯分佈,那麼由式(1-1)可得似然概率的表示式為
\[ p(\mathbf{x}|c_k)=\frac{1}{\sqrt{(2\pi)^n|\Sigma|}}\exp\left(-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})\Sigma^{-1}(\mathbf{x}-\boldsymbol{\mu})^T\right) \tag{1-5} \]
由於對所有的\(p(c_k|\mathbf{x})\) ,\(p(\mathbf{x})\) 都是一樣的,所以我們只需要對式(1-4)的分母比較大小,因此我們可以推出如下判別式
\[ \log(p(\mathbf{x}|c_k)p(c_k))=-\frac{1}{2}\log|\Sigma|-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})\Sigma^{-1}(\mathbf{x}-\boldsymbol{\mu})^T-\frac{n}{2}\log(2\pi)+\log{p(c_k)} \]
注:取對數,可以簡化我們的計算,並不影響我們對大小的判斷。更進一步地,我們可以將上式的表示式中的常數項去掉。
\[ g_k(\mathbf{x})=-\frac{1}{2}\log|\Sigma|-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})\Sigma^{-1}(\mathbf{x}-\boldsymbol{\mu})^T+\log{p(c_k)} \tag{1-6} \]
最終,我們只需要對式(1-6)進行計算,即可分出類別。
2、非樸素貝葉斯實現
2.1 準備資料
與《貝葉斯之樸素理解》第4小節
類似,我們先準備好我們的工作環境:jupyter
+python3.6
,這是我目前用的環境,如果大家沒有用過jupyter
,我建議大家用一下,相信你會愛上它的。關於jupyter的安裝和下載以及使用,我在這裡就不說了,聰明的你自會百度或google。其次,我們再準備一下資料集:CIFAR-10影象資料,我將其放入了我的百度網盤,連結:https://pan.baidu.com/s/1yIkiL7xXHsqlXS53gxMkEg
提取碼: wcc4。原始的CIFAR-10影象是一個用於普世物體識別的資料集,分為airplane、automobile、bird、cat、deer、dog、frog、horse、ship、truck共10類,但是這裡為了簡單起見,我用了其中3類。
注:由於在《貝葉斯之樸素理解》一文中詳細地說明了關於資料的讀取,這裡就不多說了,直接貼出程式碼,相信機智的你也能看懂。
下面程式碼為讀取資料(請保證資料集在當前檔案路徑下的data資料夾下)
import numpy as np import pandas as pd from scipy.io import loadmat train_data_mat = loadmat("./data/train_data.mat") test_data_mat = loadmat("./data/test_data.mat") labels_name_mat = loadmat("./data/labels_name.mat") # 訓練資料和標籤 train_data = train_data_mat["Data"] train_data_label = train_data_mat["Label"] # 測試資料和標籤 test_data = test_data_mat["Data"] test_data_label = test_data_mat["Label"] # 標籤的實際名字 label_names = labels_name_mat["label_names"] # 因為標籤名字有誤,我這裡把它手動改一下 label_names[:, 0] = ['automobile', 'bird', 'cat', 'deer', 'dog'] col_name_lst = [0]*3072 for i in range(1, 3073): col_name_lst[i-1] = "x" + str(i) # 結構化訓練集資料 train_data = pd.DataFrame(train_data, columns=col_name_lst) train_data_label = pd.DataFrame(train_data_label, columns=['class_no']) train_dataFrm = train_data.join(train_data_label) # 結構化測試集資料 test_data = pd.DataFrame(test_data, columns=col_name_lst) test_data_label = pd.DataFrame(test_data_label, columns=['class_no']) test_dataFrm = test_data.join(test_data_label) # 上面所得到的資料是全部5類的資料,下面只取出前3類資料 train_dataFrm = train_dataFrm[train_dataFrm["class_no"] <= 3] train_data = train_dataFrm.drop(columns=["class_no"], axis=1) train_data_label = train_dataFrm["class_no"].copy() test_dataFrm = test_dataFrm[test_dataFrm["class_no"] <= 3] test_data = test_dataFrm.drop(columns=["class_no"], axis=1) test_data_label = test_dataFrm["class_no"].copy() # 檢視取出3類後的基本的資料結構資訊 # print(train_data_label.shape) # print(train_data.shape) # print(test_data_label.shape) # print(test_data.shape)
2.2 實現貝葉斯
據式(1-6)實現如下貝葉斯分類器。
計算均值向量和協方差矩陣
from sklearn.decomposition import PCA # 利用PCA對原始資料進行降維 pca = PCA(n_components=21) pca.fit(train_data) train_data_pca = pca.transform(train_data) test_data_pca = pca.transform(test_data) train_data_pca = pd.DataFrame(train_data_pca, index=train_dataFrm.index) test_data_pca = pd.DataFrame(test_data_pca, index=test_dataFrm.index) # 求出每個類的均值向量和協方差矩陣 train_cls_cov = []# 協方差矩陣 train_cls_cov_inv = []#協方差矩陣的逆 train_cls_cov_det = []#協方差矩陣的行列式 train_cls_mean = []#均值向量 for i in range(0,3): train_cls_cov.append(np.cov(train_data_pca[train_dataFrm["class_no"]==1+i].T)) train_cls_cov_inv.append(np.linalg.inv(train_cls_cov[i])) train_cls_cov_det.append(np.linalg.det(train_cls_cov[i])) train_cls_mean.append(train_data_pca[train_dataFrm["class_no"]==1+i].mean())
注:上面的程式碼中利了PCA對資料進行降維,關於PCA的知識,後面有時間再討論。這裡之所以要進行降維,有兩原因,一是因為原始資料維度過高,求出它的協方差矩陣後,對其求行列式,行列式會變成0(其實此時不是0,是一個非常非常小的數,計算機無法存放,所以為0),二是因為原始資料的資料內容並純淨,PCA可以起到一個去除噪聲的作用。
對測試集資料進行預測
for img_index in range(0, test_data.shape[0]): determine_clf = [0]*3 ftr_data = test_data_pca.iloc[img_index] for i in range(0, 3): class_mean = train_cls_mean[i] class_cov = train_cls_cov[i] class_inv = train_cls_cov_inv[i] class_det = train_cls_cov_det[i] prob_temp = -(np.log(class_det)*0.5+0.5 * \ np.dot(np.dot((ftr_data-class_mean), class_inv), (ftr_data-class_mean).T)) prob_temp = prob_temp + np.log(prior_series[i+1]) determine_clf[i] = prob_temp # 取出其中最大值的索引,即為我們的預測值 pred_label[img_index] = np.argmax(determine_clf) + 1 accu = sum(pred_label == test_data_label)/len(pred_label) print("dimn:{0:3}-->accu:{1:.3f}".format(test_data_pca.shape[1], accu))
輸出
dimn: 21-->accu:0.722
可以看到,降到21維後,準確率為72.2%。