1. 程式人生 > >機器學習:貝葉斯分類器(二)——高斯樸素貝葉斯分類器代碼實現

機器學習:貝葉斯分類器(二)——高斯樸素貝葉斯分類器代碼實現

mod ces 數據 大於等於 即使 平均值 方差 很多 mode

一 高斯樸素貝葉斯分類器代碼實現

  • 網上搜索不調用sklearn實現的樸素貝葉斯分類器基本很少,即使有也是結合文本分類的多項式或伯努利類型,因此自己寫了一遍能直接封裝的高斯類型NB分類器,當然與真正的源碼相比少了很多屬性和方法,有興趣的可以自己添加。代碼如下(有詳細註釋):
class NaiveBayes():
    ‘‘‘高斯樸素貝葉斯分類器‘‘‘

    def __init__(self):

        self._X_train = None
        self._y_train = None
        self._classes = None
        self._priorlist = None
        self._meanmat = None
        self._varmat = None

    def fit(self, X_train, y_train):
        
        self._X_train = X_train
        self._y_train = y_train
        self._classes = np.unique(self._y_train)                       #  得到各個類別
        priorlist = []
        meanmat0 = np.array([[0, 0, 0, 0]])
        varmat0 = np.array([[0, 0, 0, 0]])
        for i, c in enumerate(self._classes):
            # 計算每個種類的平均值,方差,先驗概率
            X_Index_c = self._X_train[np.where(self._y_train == c)]        # 屬於某個類別的樣本組成的“矩陣”
            priorlist.append(X_Index_c.shape[0] / self._X_train.shape[0])  # 計算類別的先驗概率
            X_index_c_mean = np.mean(X_Index_c, axis=0, keepdims=True)     # 計算該類別下每個特征的均值,結果保持二維狀態[[3 4 6 2 1]]
            X_index_c_var = np.var(X_Index_c, axis=0, keepdims=True)       # 方差
            meanmat0 = np.append(meanmat0, X_index_c_mean, axis=0)         # 各個類別下的特征均值矩陣羅成新的矩陣,每行代表一個類別。
            varmat0 = np.append(varmat0, X_index_c_var, axis=0)
        self._priorlist = priorlist
        self._meanmat = meanmat0[1:, :]                                    #除去開始多余的第一行
        self._varmat = varmat0[1:, :]

    def predict(self,X_test):
        
        eps = 1e-10                                                        # 防止分母為0
        classof_X_test = []                                                #用於存放測試集中各個實例的所屬類別
        for x_sample in X_test:
            matx_sample = np.tile(x_sample,(len(self._classes),1))         #將每個實例沿列拉長,行數為樣本的類別數
            mat_numerator = np.exp(-(matx_sample - self._meanmat) ** 2 / (2 * self._varmat + eps))
            mat_denominator = np.sqrt(2 * np.pi * self._varmat + eps)
            list_log = np.sum(np.log(mat_numerator/mat_denominator),axis=1)# 每個類別下的類條件概率相乘後取對數
            prior_class_x = list_log + np.log(self._priorlist)             # 加上類先驗概率的對數
            prior_class_x_index = np.argmax(prior_class_x)                 # 取對數概率最大的索引
            classof_x = self._classes[prior_class_x_index]                 # 返回一個實例對應的類別
            classof_X_test.append(classof_x)
        return classof_X_test

    def score(self, X_test, y_test):
        
        j = 0
        for i in range(len(self.predict(X_test))):
            if self.predict(X_test)[i] == y_test[i]:
                j += 1
        return (‘accuracy: {:.10%}‘.format(j / len(y_test)))
  • 對於手動實現的高斯型NB分類器,利用鳶尾花數據進行測試,與調用sklearn庫的分類器結果差不多,基本在93-96徘徊。這是由於多次進行二八切分,相當於多次留出法。為計算更準確精度,可進行交叉驗證並選擇多個評價方法,這裏不再實現。
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
# 獲取數據集,並進行8:2切分
iris = datasets.load_iris()
X = iris.data
y = iris.target
# print(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

nb = NaiveBayes()
nb.fit(X_train,y_train)
print(nb.predict(X_test))
print(nb.score(X_test,y_test))
#輸出結果如下:
[0, 2, 1, 1, 1, 2, 1, 0, 2, 0, 1, 1, 1, 0, 2, 2, 2, 2, 0, 1, 1, 0, 2, 2, 2, 0, 1, 0, 1, 0]
accuracy: 96.6666666667%

二 其他

  • 基於屬性條件獨立性假設的樸素貝葉斯,在現實中往往很難成立,因此產生了“半樸素貝葉斯分類器”。其基本思想是適當考慮一部分屬性間的相互依賴信息,從而既不需要進行完全聯合概率計算,又不至於徹底忽略比較強的屬性依賴關系。“獨依賴估計”是最常用的一種策略,即假設每個屬性在類別之外最多依賴一個其他屬性。包括SPODE方法,TAN方法,AODE方法等。
  • np.unique():返回原來array中不重復元素組成的新array,元素從小到大。
y = np.array([1, 2, 9, 1,2,3])
classes = np.unique(y)                     # 返回y中所有不重復的元素組成的新array([1,2,3,9])
print(classes)                             # 結果為np.array([1,2,3,9])
  • np.where():對array進行操作
‘‘‘
1. np.where(condition, x, y)
滿足條件(condition),滿足進行x操作,不滿足進行y操作
‘‘‘
a= np.array([[9, 7, 3], [4, 5, 2], [6, 3, 8]])
b=np.where(a > 5, 1, 0)               #對於a中的元素如果大於5,則改寫成1,否則寫成0.                
print(b)
輸出結果:
[[1 1 0]
 [0 0 0]
 [1 0 1]]
‘‘‘
2. np.where(condition)
只有條件 (condition),沒有x和y,則輸出滿足條件元素的坐標 (等價於numpy.nonzero)。
這裏的坐標以tuple的形式給出,通常原數組有多少維,輸出的tuple中就包含幾個數組,分別對應符合條件元素的各維坐標。
‘‘‘
c = np.array([[9, 7, 3], [4, 5, 2], [6, 3, 8]])
d = np.where(c > 5)                                                #條件為元素大於5
print(d)
輸出結果如下(元組):
(array([0, 0, 2, 2], dtype=int64), array([0, 1, 0, 2], dtype=int64)) 表示下表為 00,01 20,22的元素滿足條件。

a = np.array([1,3,6,9,0])
b = np.where(a > 5)
print(b)
輸出結果(array([2, 3], dtype=int64),)表示坐標為2和3的元素滿足,註意末尾的逗號,表明一維時實質輸出元組為二維,2_,3_只不過後面沒有而已,a維數大於等於2時,元組和a維數相同。
輸出的結果是可以直接作為數組下標。
x = np.array([[1, 5, 8, 1], [2, 4, 6, 8], [3, 6, 7, 9], [6, 8, 3, 1]])
print(x[b])  結果為x的第2,3行組成的數組[[3  6 7 9]  [6  8 3 1]],等價於x[[2,3]],x[2,3]為輸出為元素9,x[[2],[3]]輸出數組[9]。

機器學習:貝葉斯分類器(二)——高斯樸素貝葉斯分類器代碼實現