700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 机器学习:朴素贝叶斯分类器代码实现 决策函数非向量化方式

机器学习:朴素贝叶斯分类器代码实现 决策函数非向量化方式

时间:2021-10-09 01:04:27

相关推荐

机器学习:朴素贝叶斯分类器代码实现 决策函数非向量化方式

文章目录

朴素贝叶斯离散型的算法描述:代码实现:实现一个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 npclass 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:])

测试数据:

/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 %

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。