机器学习:朴素贝叶斯分类器代码实现,决策函数非向量化方式
生活随笔
收集整理的這篇文章主要介紹了
机器学习:朴素贝叶斯分类器代码实现,决策函数非向量化方式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 樸素貝葉斯離散型的算法描述:
- 代碼實現:
- 實現一個NaiveBayes的基類,以便擴展:
- 實現離散型樸素貝葉斯MultiomialNB類:
- 實現從文件中讀取數據:
- 測試數據:
- 代碼測試:
樸素貝葉斯離散型的算法描述:
代碼實現:
看算法描述比較好實現,但是實際實現起來,還是有一定難度喔
有一點需要注意,在看代碼或者實現代碼過程中,你必須知道矩陣的每一個緯度是什么含義, 這是寫代碼看代碼的基礎注釋比較詳細,可以直接閱讀。
實現一個NaiveBayes的基類,以便擴展:
# -*- coding: utf-8 -*-import numpy as npclass NaiveBayes:def __init__(self):# 記錄訓練集的變量self._x = Noneself._y = None# 核心數組,儲存實際使用的條件概率的相關信息self._data = None# 模型核心,決策函數,能夠根據輸入的x,y得到對應的后驗概率self._func = None# 記錄各個維度特征值取值個數的數組self._n_possibilities = None# 記錄按照類別分開后的輸入數據的數組self._labeled_x = None# 記錄類別的信息self._label_x_zip = None# 核心數組,記錄第i類數據的個數,cat為categoryself._cat_counter = None# 核心數組,記錄數據條件概率的原始極大似然估計# self._con_counter[d][c][p] = p(X^d = p | y = c) con為conditionalself._con_counter = None# 核心數組用于記錄數值化類別時的轉換關系self.label_dic = None# 核心數組用于記錄數值化features時的轉換關系self._feat_dics = None# 重載__getitem__運算符避免定義大量的propertydef __getitem__(self,item):if isinstance(item,str):return getattr(self,"_"+item) # ============================================================================= # 模型的訓練 # =============================================================================# 留下抽象方法讓子類定義def feed_data(self,x,y,sample_weight = None):pass# 留下抽象方法讓子類定義,sample_weight代表樣本權重# 這個地方是為了后續使用提升的方法,樣本的權重體現了各個樣本的重要性def feed_sample_weight(self,sample_weight = None):pass# 定義計算先驗概率的函數,lb為各個估計中的平滑項lambda# lb的默認值為1,也就是默認使用拉普拉斯平滑def get_prior_probability(self,lb =1):return [(_c_num + lb) / (len(self._y) + lb*len(self._cat_counter)) for _c_num in self._cat_counter]# 定義具有普適的訓練def fit(self,x=None,y=None,sample_weight=None,lb=1):# 如果有傳入的x,y就把x,y傳入初始化模型if x is not None and y is not None:self.feed_data(x,y,sample_weight)# 調用核心算法得到決策函數self._func = self._fit(lb)# 留下核心算法讓子類定義def _fit(self,lb):pass# ============================================================================= # 模型的評估和預測 # ============================================================================= # 定義預測單一樣本的函數 # 參數get_raw_result為控制函數是輸出類別(False)還是輸出后驗概率(True)def predict_one(self,x,get_raw_result=False):# 將輸入的數據數值化,如果是numpy數組,轉化成python的list# 這時因為python在數值化這個操作上list比較快if isinstance(x,np.ndarray):x = x.tolist()else:x = x[:]# 調用相關方法數值化,該方法具體的模型不同而不同x = self._transfer_x(x)# 類別和該類別的后驗概率,存的是當前最大的m_arg,m_probability = 0,0# 遍歷各個類別找到最大的后驗概率的類別for i in range(len(self._cat_counter)):# 決策函數p = self._func(x,i)if p > m_probability:m_arg,m_probability = i, pif not get_raw_result:return self.label_dic[m_arg]return m_probability# 預測多個樣本,就是重復調用一個樣本def predict(self,x,get_raw_result=False):return np.array([self.predict_one(xx,get_raw_result) for xx in x])# 定義評估方法,在這里使用準確率來定義def evaluate(self,x,y):y_pred = self.predict(x)print("Acc: {:12.6} %".format(100*np.sum(y==y_pred)/len(y)))實現離散型樸素貝葉斯MultiomialNB類:
# -*- coding: utf-8 -*- # ============================================================================= # 處理離散性的樸素貝葉斯 # =============================================================================from Basic_bayes import NaiveBayesimport numpy as npclass MultiomialNB(NaiveBayes):# 定義數據預處理def feed_data(self,x,y,sample_weight=None):# 分情況將輸入的向量轉置,原始x每一行[feature1,feature2..]# 轉置后,每一行為一個feature的那個樣本的取值if isinstance(x,list):features = map(list,zip(*x))else:features = x.T# 一般的二維數據數值化的思路的,建立二維數值化的字典,注意之間的對應關系# 一般情況下特征數量*樣本數量--》特征數量*每個特征的取值范圍,就得到了特征特征值# 的數值化了,將原數據轉化為數值化,遍歷數據時,注意是遍歷 特征:特征值,指針是特征# 這樣就可以使用字典訪問了,也就是一個一個數據的訪問就可以了。# 使用set獲取各個維度的特征和類別種類,# 使用bincount優化算法,將所有特征從0開始數值化# 將數值化的過程轉化成字典,這樣一一對應# 獲取的是每一個feature的取值features = [set(feat) for feat in features]# feat_dics[第幾個feature][這個feature的取值] = 這個feature的取值對應的數值化IDfeat_dics = [{_:i for i,_ in enumerate(feats)} for feats in features ]label_dic = {_:i for i,_ in enumerate(set(y))}# 利用字典轉換更新數據集# 這里可能有點難以理解,自己舉個例子就能明白# feat_dics每一行代表一個feature緯度# 每一行里裝的是:這個feature的取值:數值化這個feature的取值# 原始x每一行[feature1,feature2..],遍歷它,就是第幾個featurex = np.array([[feat_dics[i][_] for i,_ in enumerate(sample)] for sample in x])y = np.array([label_dic[yy] for yy in y])# 利用numpy里面的bitcount方法統計各個類別的數量cat_counter = np.bincount(y)# 記錄各個緯度特征的取值個數n_possibilities = [len(feats) for feats in features]# 這里給出了一般的:將數據集按照類別分類的方法# 數值化之后處理,操作對象必須為numpy# y == value 就可以標記出出分為為value的數據,標記的數據為True# x[ci].T,ci為標記數組,就可以得到標記的數據# 獲取各類別數據的下表# 這個得到的是len(cat_counter)個array,每個array look like y,里面都是True or False# 表明每個類別在y中的位置labels = [y == value for value in range(len(cat_counter))]# labels返回的是類別個數的表,每個表記錄了每個類別在數據中的標記# x[labels[0]]可以得到,標記數組標記的數據,轉置了,代表現在矩陣為feature數目*數據個數labeled_x = [x[ci].T for ci in labels]# 更新各個模型的屬性 # ============================================================================= # self._x:[datanum,feature] = featureValue , # self._y:[datanum] = class # self._labeled_x:[class,feature,num_in_class] = featureValue # self._cat_counter:[class] = num_in_class # self._feat_dics:[feature,featureValue] = encodefeatureValue # self._n_possibilities:[feature] = num_in_feature # =============================================================================self._x,self._y = x,yself._labeled_x,self._label_x_zip = labeled_x,list(zip(labels,labeled_x))(self._cat_counter,self._feat_dics,self._n_possibilities) = (cat_counter,feat_dics,n_possibilities)self.label_dic = {i:_l for _l,i in label_dic.items()}# 調用處理呀根本權重的函數,以便更新記錄條件概率的數組self.feed_sample_weight(sample_weight)# 定義處理樣本權重的函數def feed_sample_weight(self,sample_weight=None):# self._con_counter:[feature,class,featureValue] = p(x =(feature,featureValue)|y = class)self._con_counter = []# 用于求條件概率的極大似然估計,x =(feature,featureValue)的數量# dim = feature, _p = num_in_featurefor dim,_p in enumerate(self._n_possibilities):if sample_weight is None:# xx:[feature,num_in_class],需要統計xx里面,不同featureValue的數量# 被添加進來的數據為:[class,featureValue] = num_in_featureValue# 外部循環后就為:[feature,class,featureValue]self._con_counter.append([np.bincount(xx[dim],minlength=_p) for xx in self._labeled_x])else:self._con_counter.append([np.bincount(xx[dim],weights=sample_weight[label] / sample_weight[label].mean(),minlength=_p)for label,xx in self._label_x_zip])# 定義核心處理函數def _fit(self,lb):# n_dim為feature的個數n_dim = len(self._n_possibilities)# n_category 為class的數目n_category = len(self._cat_counter)# 先驗概率[class] = prior_probabilityp_category = self.get_prior_probability(lb)# data儲存平滑處理后的條件概率數組data = [None]*n_dim# self._n_possibilities:[feature] = num_in_featurefor dim,n_possibilities in enumerate(self._n_possibilities):data[dim] = [[(self._con_counter[dim][c][p] + lb) / (self._cat_counter[c] + lb*n_possibilities)for p in range(n_possibilities)] for c in range(n_category)]# 以上得到的data:[feature,class,featureValue]self._data = [np.array(dim_info) for dim_info in data]# 利用self._data生成決策函數def func(input_x,tar_category):rs =1# 遍歷各個緯度,利用data和條件獨立假設計算聯合條件概率# d,xx:feature,featureValuefor d,xx in enumerate(input_x):rs *= data[d][tar_category][xx]# 利用先驗概率和聯合條件概率計算后驗概率return rs*p_category[tar_category]# fit里需要返回決策函數return func# 定義數值化數據的函數,就是預測的時候,需要處理以下預測的數據def _transfer_x(self,x):# 遍歷每一個元素,利用轉化字典進行數值化# self._feat_dics:[feature,featureValue] = encodefeatureValue# 這時對單個數據的處理# j,char :feature,featureValuefor j,char in enumerate(x):x[j] = self._feat_dics[j][char]return x實現從文件中讀取數據:
# -*- coding: utf-8 -*-# 定義一個將文件中的數據轉化為數組的類 import numpy as np class DataUtil: # ============================================================================= # 從文件中讀取數據 # 5個參數:數據集的名稱,數據集的路徑,訓練樣本數,類別所在列,是否打亂數據 # =============================================================================def get_dataset(name,path,train_num=None,tar_index=None,shuffle=True):x =[]# 將編碼設置為utf-8with open(path,"r",encoding="utf-8") as file:# 如果是氣球數據集的話,使用逗號分割數據if "balloon" in name:# 文件讀取是一行一行讀取的for sample in file:# 一行數據就是一個數組,strip()去空格,split(",")以逗號分隔x.append(sample.strip().split(","))# 默認打亂數據if shuffle:np.random.shuffle(x)# 默認類別在最后一列tar_index = -1 if tar_index is None else tar_indexy = np.array([xx.pop(tar_index) for xx in x])x = np.array(x)# 默認是全部訓練樣本if train_num is None:return x,y# 若傳入了訓練樣本樹,則分為訓練集和測試集return (x[:train_num],y[:train_num]),(x[train_num:],y[train_num:])測試數據:
https://pan.baidu.com/s/14ecC-61qXaCjyryz-PrepQ
代碼測試:
if __name__ == '__main__':from Util import DataUtilfor dataset in ("balloon1.0","balloon1.5","balloon2.0"):# 讀取數據_x,_y = DataUtil.get_dataset(dataset,"_Data/{}.txt".format(dataset))# 實例化模型,并進行訓練nb = MultiomialNB()nb.fit(_x,_y)# 評估模型nb.evaluate(_x,_y)Acc: 100.0 % Acc: 91.6667 % Acc: 100.0 %總結
以上是生活随笔為你收集整理的机器学习:朴素贝叶斯分类器代码实现,决策函数非向量化方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据预处理:读取文件数据,并存为pyth
- 下一篇: 机器学习:朴素贝叶斯分类器,决策函数向量