精华内容
下载资源
问答
  • 2022-03-15 14:20:00

    算法优劣

    优点:

    1. 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率。

    2. 对小规模的数据表现很好,能个处理多分类任务,适合增量式训练,尤其是数据量超出内存时,我们可以一批批的去增量训练。

    3. 对缺失数据不太敏感,算法也比较简单,常用于文本分类。

    缺点

    1. 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。

    2. 需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。

    3. 由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。

    4. 对输入数据的表达形式很敏感。

    算法实现

    说明

    • scikit-learn中,一共有3个朴素贝叶斯的分类算法类。分别是GaussianNBMultinomialNBBernoulliNB
    • GaussianNB:先验为高斯分布的朴素贝叶斯
    • MultinomialNB:先验为多项式分布的朴素贝叶斯
    • BernoulliNB:先验为伯努利分布的朴素贝叶斯。

    数据准备

    import pandas as pd
    import numpy as np
    X = np.array([[1.14, 1.78],[1.18, 1.96],[1.20, 1.86],[1.26, 2.00],[1.28, 2.00],
                 [1.30, 1.96],[1.24, 1.72],[1.36, 1.74],[1.38, 1.64],[1.38, 1.82],
                 [1.38, 1.90],[1.40, 1.70],[1.48, 1.82],[1.54, 1.82],[1.56, 2.08]])
    Y = np.hstack((np.ones(6), np.ones(9)*2)) #数组合并
    

    GaussianNB预测

    from sklearn.naive_bayes import GaussianNB
    clf_Ga = GaussianNB()
    clf_Ga.fit(X, Y)
    print("预测结果")
    print(clf_Ga.predict([[1.24, 1.80]]))
    print("样本为1类的概率")
    print(clf_Ga.predict_proba([[1.24, 1.80]]))
    print("样本为2类的概率")
    print(clf_Ga.predict_log_proba([[1.24, 1.80]]))
    

    输出:

    预测结果
    [1.]
    样本为1类的概率
    [[0.7236103 0.2763897]]
    样本为2类的概率
    [[-0.3235023  -1.28594344]]
    
    • 样本为1的概率大于样本为2的概率,所以认为该样本为1类
    print("预测结果")
    print(clf_Ga.predict([[1.29, 1.81],[1.43,2.03]]))
    

    输出:

    预测结果
    [2. 2.]
    

    MultinomialNB预测

    • 这里使用GridSearchCV函数进行网格搜索交叉检验调参,评估模型的分数为accuracy即准确率。
    • 调整的参数分别为:alpha(常数 λ \lambda λ),fit_prior(是否考虑先验概率)
    from sklearn.naive_bayes import MultinomialNB
    clf_Mu = MultinomialNB()
    from sklearn.model_selection import GridSearchCV
    param_grid = [{'alpha':np.arange(0.9,1.1,0.1),
                  'fit_prior':['True','False']}]
    grid_search = GridSearchCV(clf_Mu, param_grid, cv = 3,
                              scoring = 'accuracy',
                              return_train_score = True)
    grid_search.fit(X,Y)
    

    输出最优参

    grid_search.best_params_
    

    输出:

    {'alpha': 0.9, 'fit_prior': 'True'}
    

    查看网格搜索模型分数

    cvres = grid_search.cv_results_
    for accuracy,params in zip(cvres["mean_test_score"],cvres["params"]):
        print("{:.2}".format(accuracy),params)
    

    输出:

    0.6 {'alpha': 0.9, 'fit_prior': 'True'}
    0.6 {'alpha': 0.9, 'fit_prior': 'False'}
    0.6 {'alpha': 1.0, 'fit_prior': 'True'}
    0.6 {'alpha': 1.0, 'fit_prior': 'False'}
    0.6 {'alpha': 1.1, 'fit_prior': 'True'}
    0.6 {'alpha': 1.1, 'fit_prior': 'False'}
    
    • 这里可能是因为样本只有15个,导致参数不管如何变化对准确率都没有太大影响。

    预测结果

    final_model = grid_search.best_estimator_
    
    X_test = np.array([[1.24, 1.80],[1.29, 1.81],[1.43,2.03]])
    X_test_prepared = final_model.predict(X_test)
    print("预测结果")
    print(X_test_prepared)
    

    输出:

    预测结果
    [2. 2. 2.]
    

    结语

    • 两种方法在对第1个样本的预测上有不同,这里因为样本数量太少,不做深究。
    更多相关内容
  • 一个实现朴素贝叶斯分类器简单的Python
  • 朴素贝叶斯分类器python版)

    热门讨论 2014-08-04 18:06:25
    python写的简单的朴素贝叶斯分类器,一共有两个主文件,nbayes1和nbayes1_run1还有两个训练数据文件,望大家多多指教。
  • #将不同分类的属性进行分别存放,为了可以分别计算均值和标准差 def classfiAttr ( Attr , Label ) : Attr_have = [ ] Attr_no = [ ] for i in range ( len ( Label ) ) : if Label [ i ] == 1 :...
    import xlrd
    import random
    import math
    
    #将表格文件进行导入
    def loaddata(fname):
        file=open(fname)
        data=xlrd.open_workbook(fname) #将表格的内容进行读取
        dataname=data.sheet_names() #生成的是一个列表
        #shxrange=range(data.nsheets)
        #print(shxrange)
        try:
            sh=data.sheet_by_name(dataname[0])
        except:
            print("no sheet %s named Sheet1".format(fname))
        nrows=sh.nrows
        ncols=sh.ncols
        print("nrows {0},ncols {1}".format(nrows,ncols))
    
        datasets=[]
    
        for i in range(nrows):
            datasets.append(sh.row_values(i))
        del datasets[0]
    
        return datasets
    
    #测试程序,用的是自己建立的表格数据
    #dataset=loaddata("E:\\pima_data\\test_data.xlsx")
    #print("dataset",dataset)
    #print(len(dataset))
    
    #训练集和测试集进行分割
    def splitDataset(dataset,splitRatio):
        trainSet=[]
        dataSet_copy=dataset
        trainSize=(len(dataset))*splitRatio
        n=0
        while trainSize>n:
            index=random.randrange(len(dataSet_copy))
            #表示在数据集中任意选择样本,保证样本的随机性
            trainSet.append(dataSet_copy[index])
            dataSet_copy.pop(index)
            n+=1
        testSet=dataSet_copy
    
        return trainSet,testSet  #返回的是包含每一个样本的列表
    
    
    #进行程序的测试
    #(trainSet,testSet)=splitDataset(dataset,0.6)
    #print("trainSet",trainSet)
    #print("testSet",testSet)
    
    #对属性和标签进行分别存放
    def splitAttrLabel(dataSet):
        #对于训练集和测试集是一样的处理,所以使用一个函数就可以进行处理
        Attr=[]
        Label=[]
        num=len(dataSet) #表示数据集中样本的数量
        n_attr=len(dataSet[0])-1  #为了代码的重复利用,不用修改参数
        for i in range(num):
            Attr.append(list(dataSet[i][0:n_attr])) #生成包含每个样本属性的列表属性列表
            Label.append(dataSet[i][n_attr])        #生成包含每个标签的标签列表
    
        return Attr,Label
    
    #属性应该分为有糖尿病的属性是什么,没有糖尿病的属性是什么
    #但是可以不定义函数,直接在程序中写出来
    
    #测试
    #(Attr,Label)=splitAttrLabel(trainSet)
    #print("trainSet Attr",Attr)
    #print("trainSet Label",Label)
    
    #将不同分类的属性进行分别存放,为了可以分别计算均值和标准差
    def classfiAttr(Attr,Label):
        Attr_have=[]
        Attr_no=[]
        for i in range(len(Label)):
            if Label[i]==1:
                Attr_have.append(Attr[i])
            else:
                 Attr_no.append(Attr[i])
        return Attr_have,Attr_no
    
    #测试
    #(Attr_have,Attr_no)=classfiAttr(Attr,Label)
    #print("糖尿病患者属性列表",Attr_have)
    #print("非糖尿病患者属性列表",Attr_no)
    
    
    #因为是连续的数值,
    # 所以使用贝叶斯公式对数值进行处理得到各个属性的类条件概率
    #由最大似然法得到正太分布的均值就是样本均值
    def stmean(Attr):
    
        attr_mean=[]   #将8个属性的平均值都放到这个列表中作为向量使用
        for each_attr in range(len(Attr[0])):
            #print("属性的长度是多少",len(Attr[0]))
            #print(each_attr)
            sum=0
            for each_example in range(len(Attr)):
                #print(Attr[each_example][each_attr])
                sum+=Attr[each_example][each_attr]
            attr_mean.append(sum/len(Attr))
    
            #each_attr_mean=(sum(Attr[:][each_attr]))/(len(Attr))
            #print(Attr[:])
            #attr_mean.append(each_attr_mean)
    
        return attr_mean
    
    #进行测试
    #stmean_no=stmean(Attr_no)
    #print("trainSet stmean_no",stmean_no)
    
    #标准差
    #标准差就是样本的平均标准差
    def stdev(Attr,stmean):
    
        attr_dev=[]   #将8个属性的平均值都放到这个列表中作为向量使用
        for each_attr in range(len(Attr[0])):
            sum=0
            for each_example in range(len(Attr)):
                #print("函数内",stmean[each_attr])
                sum+=pow((Attr[each_example][each_attr]-stmean[each_attr]),2)
            attr_dev.append(math.sqrt(sum/len(Attr)))
    
        return attr_dev
    
    #测试
    #stdev_no=stdev(Attr_no,stmean_no)
    #print("标准差",stdev(Attr_no,stmean_no))
    
    #定义类概率密度函数
    
    def calculateProbability(x, mean, stdev):
      exponent = math.exp(-(math.pow(x-mean,2)/(2*math.pow(stdev,2))))
      return (1 / (math.sqrt(2*math.pi) * stdev)) * exponent
    
    #测试
    #Probability=calculateProbability(4, stmean_no[0], stdev_no[0])
    #print("单个值单属性的类条件概率",Probability)
    
    #计算类别的先验概率
    def calculatepriorprobability(Attr,Attr_have,Attr_no):
        probability_have=(len(Attr_have)+1)/(len(Attr)+2)
        probability_no=(len(Attr_no)+1)/(len(Attr)+2)
        return probability_have,probability_no
    
    #测试
    #(probability_have,probability_no)=calculatepriorprobability(Attr_have,Attr_no)
    #print("有糖尿病的先验概率是:",probability_have)
    #print("没有糖尿病的先验概率是:",probability_no)
    
    #进行测试集的预测
    def predict(priorprobability,Attr_test,mean,stdev):
    
        lateprobability_list=[]
        for each_example in range(len(Attr_test)):
            lateprobability = priorprobability
            for each_attr in range(len(Attr_test[0])):
                lateprobability*=calculateProbability(Attr_test[each_example][each_attr], mean[each_attr], stdev[each_attr])
                #print("测试集的属性值",Attr_test[each_example][each_attr])
                #print(lateprobability)
            lateprobability_list.append(lateprobability)  #生成测试集相同数量的后延概率的列表
        return lateprobability_list
    
    #将有糖尿病和没有糖尿病的预测概率进行比较,谁大就是谁
    def compare(lateprobability_list_have,lateprobability_list_no):
        compare_list=[]
        for i in range(len(lateprobability_list_have)):
            if lateprobability_list_have[i]>=lateprobability_list_no[i]:
                compare_list.append(1)
            else:
                compare_list.append(0)
        return compare_list
    
    #精度函数
    def predict_precision(test_label,compare_list):
        n=0 #表示这个时候没有一个数据正确
        for i in range(len(test_label)):
            if test_label[i]==compare_list[i]:
                n+=1
        print(n)
        precision=n/(len(test_label))
        return precision
    
    #定义主函数
    def main():
        fname="E:\\datasets\\pima_data\\pima.xlsx"
        dataset=loaddata(fname) #将数据集导入
        (trainSet,testSet)=splitDataset(dataset, 0.67) #将数据集进行分割,分割成训练集和测试集
        print("训练集为:",trainSet,"\n训练集数目为:",len(trainSet))
        print("测试集为:", testSet,"\n测试集数目为:",len(testSet))
        (train_attr,train_label)=splitAttrLabel(trainSet) #将训练集的属性和标签进行分割
        (test_attr, test_label) = splitAttrLabel(testSet) #测试集的属性和标签进行单独分割
        print("测试集的标签:",test_label,"\n测试集标签数目为:",len(test_label))
        (train_Attr_have,train_Attr_no)=classfiAttr(train_attr,train_label) #对训练集的属性值进行分别存放
        train_mean_have=stmean(train_Attr_have) #糖尿病人的属性均值
        print("训练集中有糖尿病的均值为",train_mean_have)
        train_mean_no=stmean(train_Attr_no)     #非糖尿病人的属性均值
        print("训练集中没有糖尿病的均值为", train_mean_no)
        train_dev_have=stdev(train_Attr_have, train_mean_have)
        print("训练集中有糖尿病的方差为", train_dev_have)
        train_dev_no=stdev(train_Attr_no, train_mean_no)
        print("训练集中没有糖尿病的方差为", train_dev_no)
        (prior_probability_have, prior_probability_no)=calculatepriorprobability(train_attr,train_Attr_have,train_Attr_no)
        print("训练集中有和没有糖尿病的先验概率为:",prior_probability_have, prior_probability_no)
    
    
        lateprobability_list_have=predict(prior_probability_have, test_attr, train_mean_have, train_dev_have)
        print("有糖尿病的后验概率表",lateprobability_list_have)
        lateprobability_list_no=predict(prior_probability_no, test_attr, train_mean_no, train_dev_no)
        print("没有糖尿病的后验概率表", lateprobability_list_no)
        compare_list=compare(lateprobability_list_have, lateprobability_list_no)
        print("通过比较得出的比较值0,1值",compare_list)
        precision=predict_precision(test_label, compare_list)
        return precision
    
    precision=main()
    print("精度为:",precision)
    

    使用pima数据集作为训练集和测试集,准确率可以达到74.7。

    展开全文
  • 伯努利朴素贝叶斯分类器主要用于文本分类,下面我们以一个具体的例子,来讲述下伯努利朴素贝叶斯的原理和实现逻辑。 具体例子: 已知我们有八个句子以及每个句子对应的类别,即中性或侮辱性。那么再给出一个句子,...
  • 本文实例讲述了Python实现的朴素贝叶斯分类器。分享给大家供大家参考,具体如下: 因工作中需要,自己写了一个朴素贝叶斯分类器。 对于未出现的属性,采取了拉普拉斯平滑,避免未出现的属性的概率为零导致整个条件...
  • 用的模型也是最简单的,就是用贝叶斯定理P(A|B) = P(B|A)*P(A)/P(B),计算每个类别在样本中概率(代码中是pLabel变量) 以及每个类下每个特征的概率(代码中是pNum变量)。 写得比较粗糙,对于某个类下没有此特征的...
  • 朴素贝叶斯分类器

    2021-01-06 21:45:00
    朴素贝叶斯分类器是基于贝叶斯公式的概率分类器,是建立在独立性假设基础上的。   贝叶斯公式可以把求解后验概率的问题转化为求解先验概率的问题,一般情况下后验概率问题 难以求解。例如;一封邮件是垃圾邮件的...
  • 多项式朴素贝叶斯也是多用于文本处理,其原理和计算的流程和伯努利朴素贝叶斯基本一致,唯一的区别在于单词的计数方式,由《伯努利朴素贝叶斯》一文可知,在文本处理的环节中,我们将单词是否出现在词组作为特征,但...
  • 朴素贝叶斯分类器中的一个假设是:每个特征同等重要 函数 loadDataSet() 创建数据集,这里的数据集是已经拆分好的单词组成的句子,表示的是某论坛的用户评论,标签1表示这个是骂人的 createVoca
  • 频率学派和贝叶斯学派 说起概率统计,不得不提到频率学派和贝叶斯学派,通过对概率的不同理解而演变的两个不同的概率学派。 频率学派 核心思想:需要得到的参数​是一个确定的值,虽然未知,但是不会因为样本的...

    目录

    频率学派和贝叶斯学派

    朴素贝叶斯分类器

    python实现朴素贝叶斯分类器


    频率学派和贝叶斯学派

    说起概率统计,不得不提到频率学派和贝叶斯学派,通过对概率的不同理解而演变的两个不同的概率学派。

    频率学派

    • 核心思想:需要得到的参数​\Theta是一个确定的值,虽然未知,但是不会因为样本X的变化而变化,样本​数据随机产生的,因此在数据样本无限大时,其计算出来的频率即为概率。其重点主要在于研究样本空间,分析样本X​的分布

    • 延展应用:最大似然估计(MLE)

    贝叶斯学派

    • 核心思想:需要得到的参数\Theta​是随机变量,而样本​X则是固定的,其重点主要在于研究参数\Theta​​的分布。 

      由于在贝叶斯学派中参数​\Theta​的是随机变量,是随着样本信息而变化的,所以贝叶斯学派提出了一个思考问题的固定模式:先验分布\pi(\theta)+样本信息\chi->后验分布​(\theta|x)。 

    • 延展应用:最大后验估计(MAP)

    • 贝叶斯公式

      假设A的先验概率为P(A),B的先验概率为P(B),B发生的条件下A发生的后验概率为P(A|B),A发生的条件下B发生的后验概率为P(B|A),则有

    P(AB)=P(A|B)P(B)=P(B|A)P(A)

    化简可得:

    P(A|B)=\frac{P(B|A)P(A)}{P(B)}

    其中A表示一种预测结果;B表示一组观测数据;P(A)表示A的先验概率,即在未观测到B之前A的概率;P(A|B)表示A的后验概率,即在观测到B之后A的概率;P(B|A)为似然函数(likelihood);P(B)为证据因子(model evidence)

    该公式可以理解为后验概率=先验概率\times调整因子​,在上式中,后验概率为​P(A|B),先验概率为​P(A),调整因子为​\frac{P(B|A)}{P(B)}

    朴素贝叶斯分类器

    基于贝叶斯定理,延伸出了一个异常朴素的分类算法--朴素贝叶斯分类器,其基本思想为:在给定条件下,计算各可能类别的概率,取最大极为预测值。从上述思想可以确切的明白,朴素贝叶斯适用于离散数据,下面将给出其数学描述。

    设​x=\{a_1,a_2,...,a_m\}为输入,​a_i为x​的特征属性,假设其特征属性都是相互独立的,需要预测​x是​C=\{y_1,y_2,...,y_n\}中的哪一类

    根据贝叶斯分分类器的思想,应该为概率最大的类别,即如果​P(y_i|x)_=\mathop{arg max}\limits_{y_i\in{V}}P(y_i|a_1,a_2,...,a_m),则有​,根据贝叶斯定理,每个类别的概率为:

    可以发现其分母与i无关,因此可以仅通过分子来比较不同类别的概率。

    P(y_i|x)=\frac{P(y_i)P(x|y_i)}{P(X)}=\frac{P(y_i)\Pi_{j=1}^{m}P(a_j|y_i)}{P(X)}

    python实现朴素贝叶斯分类器

    import pandas as pd
     ​
     def load_data(path,sep=',',encoding='utf=8'):
         '''读取数据,输入数据需要有表头
         return dataframe'''
         filetype = path.split('.')[-1]
         if filetype in ['csv', 'txt']:
             data = pd.read_csv(path, sep=sep, encoding=encoding)
         if filetype == 'xslx':
             data = pd.read_excel(path)
         return data
     ​
     ​
     def cal_prob(data,col,res):
         '''计算出现频率'''
         count_all = len(data[col])
         count_res = len(data[data[col]==res])
     ​
         return count_res/count_all
     ​
     ​
     def cal_prio_prob(data, label):
         '''计算先验概率
         return {res1:prob1, res2:prob2,...}'''
         prio_prob = {}
         for res in data[label].unique():
             prob = cal_prob(data, label, res)
             prio_prob[res] = prob
         
         return prio_prob
     ​
     ​
     def cal_likelihood_prob(data, label, input):
         '''计算似然函数
         return {res1:prob1, res2:prob2,...}'''
         likelihood_prob = {}
         for res in data[label].unique():
             data_p = data[data[label]==res]
             prob = 1
             for col in data:
                 if col != label:
                     prob = prob * cal_prob(data_p, col, input[col])
             likelihood_prob[res] = prob
         
         return likelihood_prob
     ​
     ​
     def bayes_classifier(path, label, input):
         '''比较输出最可能的类别'''
         data = load_data(path)
         prio_prob = cal_prio_prob(data, label)
         likelihood_prob = cal_likelihood_prob(data, label, input)
         max = 0
         for c in prio_prob.keys():
             prob = prio_prob[c] * likelihood_prob[c]
             print(f'{c}的结果为{prob}')
             if prob > max:
                 cla = c
                 max = prob
         
         print(f'在{input}情况下,{label}的结果为{cla}')
         
         
     if __name__=='__main__':
         path = 'weather.csv'
         label = 'PlayTennis'
         input = {'Outlook':'Sunny', 'Temperature':'Cool','Humidity':'High','Wind':'Strong'}
         bayes_classifier(path, label, input)

    稍微改进了一下,封装成接口,代码如下:

    import pandas as pd
    
    
    class naiveBayesClassfier():
        '''贝叶斯分类器
        fit: 训练分类器
        predict:预测分类结果'''
        def __init__(self, data, label):
            # 特征
            self.features = [x for x in data.columns.tolist() if x!=label]
            # 结果分类
            self.res = data[label].unique()
            # 先验概率
            self.prio_prob = {}
            # 似然函数
            self.liklihood_prob = {}
            # 证据因子
            self.evidence_prob = {}
    
        def fit(self, data, label):
            '''训练朴素贝叶斯分类器
            - data: 输入数据
            - label: 预测值
            return: 概率 '''
            row, _ = data.shape
            # 先验概率
            for i, j in data[label].value_counts().to_dict().items():
                self.prio_prob[i] = j/row
            # 似然函数
            for l in data[label].unique():
                data_n = data[data[label]==l]
                row_n, _ = data_n.shape
                prob2 = {}
                for col in self.features:
                    prob1 = {}
                    for i, j in data_n[col].value_counts().to_dict().items():
                        prob1[i] = j/row_n
                    prob2[col] = prob1
                self.liklihood_prob[l] = prob2
            # 证据因子
            for col in self.features:
                prob3 = {}
                for i, j in data[col].value_counts().to_dict().items():
                    prob3[i] = j/row
                self.evidence_prob[col] = prob3
    
        def cal_prob(self, input, res):
            '''计算似然概率,证据因子'''
            liklihood = 1
            evidence = 1
            for col in input.keys():
                print(col)
                v = input[col]
                liklihood = liklihood * self.liklihood_prob[res][col][v]
                evidence = evidence * self.evidence_prob[col][v]
    
            return liklihood, evidence
    
        def predict(self, input):
            '''分类器预测
            - input:需要预测的数据
            return:预测的结果及概率'''
            prob = {}
            for res in self.res:
                liklihood, evidence = self.cal_prob(input, res)
                prob[res] = self.prio_prob[res]*liklihood/evidence
    
            print(prob)
            prediction = max(prob, key=lambda x: prob[x])
            probability = prob[prediction]
            
            return prediction, probability
    
    
    # 使用
    import pandas as pd
    import naiveBayesClassfier
    
    data = pd.read_csv('weather.csv')
    label = 'PlayTennis'
    model = naiveBayesClassfier.naiveBayesClassfier(data, label)
    input = {'Outlook':'Sunny', 'Temperature':'Cool','Humidity':'High','Wind':'Strong'}
    # 训练模型
    model.fit(data, label)
    # 预测
    prediction, probability = model.predict(input)
    

    参考贝叶斯公式由浅入深大讲解

    展开全文
  • 贝叶斯分类算法是统计学的一种分类算法,利用概率统计对数据进行分类,含数据集,Python实现贝叶斯分类算法
  • Python实现朴素贝叶斯分类器

    千次阅读 2021-01-14 20:08:48
    我将数据集转成了csv格式方便Python读取: 青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是 乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是 乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是 青绿,蜷缩,沉闷,清晰,凹陷,...

    0. 算法简介及数据集

    算法的测试数据集是西瓜数据集3.0:
    在这里插入图片描述
    我将数据集转成了csv格式方便Python读取:

    青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.46,是
    乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是
    乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是
    青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是
    浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是
    青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是
    乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是
    乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是
    乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否
    青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否
    浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否
    浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否
    青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否
    浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否
    乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.36,0.37,否
    浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否
    青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否
    

    对于算法的介绍,这里将西瓜书的简介搬上来:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    1. Python实现

    代码中实现了懒惰学习和查表学习两种方法

    1.1 朴素贝叶斯的类

    import numpy as np
    
    class naiveBayes():
        """
        一个朴素贝叶斯分类器
        attrs -- 存放属性的字典, 字典中,键为属性名,值为属性的取值,最后一个属性为标签属性
        attr_idx -- 属性列索引号
        my_dic -- 存放每个标签的样本数
        mxiy_dic -- 存放每个标签的条件下,每个属性的某个属性值所含的样本数
        m -- 训练样本总数量
        attr_type -- 属性类型列表,1表示离散属性,0表示连续属性
        """
        def __init__(self):
            self.attrs = None
            self.attr_idx = None
            self.my_dic = None
            self.mxiy_dic = None
            self.m = None
            self.attr_type = None
    
        def get_attrs(self, data, attr_type):
            """
            对数据集进行处理,得到属性与对应的属性取值
            args:
            data -- 输入的数据矩阵, shape=(samples+1, features+1), dtype='<U?', 其中,第一行为属性,最后一列为标签
            attr_type -- 属性离散或连续的标记列表,1为离散,0为连续
            returns:
            attrs -- 存放属性的字典, 字典中,键为属性名,值为属性的取值 
            """
            attrs = {}
            attr_type.append(1)
            for i in range(data.shape[1]):
                if attr_type[i] == 1:
                    attrs_values = sorted(set(data[1:, i]))
                else:
                    attrs_values = []
                attrs[data[0][i]] = attrs_values
    
            self.attrs = attrs
    
        def fit(self, data, attr_type):
            """
            拟合数据,获得查询表
            args:
            data -- 输入的数据矩阵, shape=(samples+1, features+1), dtype='<U?', 其中,第一行为属性,最后一列为标签
            attr_type -- 属性离散或连续的标记列表,1为离散,0为连续
            """
            self.attr_type = attr_type
            self.get_attrs(data, attr_type)
            X = data[1:, :-1]
            y = data[1:, -1]
    
            # 先创建一个不含label属性的纯变量属性字典
            pure_attrs = self.attrs.copy()
            del(pure_attrs['label'])
            # 构造一个只含属性名的列表
            attr_names = [attr_name for attr_name in pure_attrs.keys()]
            # 将属性名编号,方便查找其在数据中对应的列
            attr_idx = {}
            for num, attr in enumerate(attr_names):
                attr_idx[attr] = num
            self.attr_idx = attr_idx
    
            self.create_search_dic(X, y, attr_type)
    
        def create_search_dic(self, X, y, attr_type):
            """
            创建查询字典
            args:
            X -- 训练集数据,shape=(samples, features)
            y -- 训练集标签,shape=(samples, )
            attr_type -- 属性离散或连续的标记列表,1为离散,0为连续
            """
            my_dic = {}
            mxiy_dic = {}
    
            m = np.size(y)
            self.m = m
            # 获取每个标签的样本数
            for label in self.attrs['label']:
                n = np.sum(y == label)
                my_dic[label] = n
    
            # 获取每个标签的条件下,每个属性的某个属性值的数量(离散)或每个属性的方差和均值(连续)
            for label in self.attrs['label']:
                mxiy_dic[label] = {}
                for attr in self.attrs:
                    if attr != 'label':
                        mxiy_dic[label][attr] = {}
                        attr_line = X[:, self.attr_idx[attr]]
                        if attr_type[self.attr_idx[attr]] == 1:
                            for attr_value in self.attrs[attr]:
                                mxiy_dic[label][attr][attr_value] = np.sum(attr_line[np.where(y==label)] == attr_value)
                        else:
                            sample = attr_line[np.where(y==label)].astype('float')
                            var = np.var(sample, ddof=1)
                            mean = np.mean(sample)
                            mxiy_dic[label][attr] = [var, mean]
            
            self.my_dic = my_dic
            self.mxiy_dic = mxiy_dic
    
        def predict(self, X, L=True, **kwargs):
            """
            预测数据
            args:
            X -- 预测数据的属性值,shape=(samples, features)
            L -- 是否使用拉普拉斯修正
            N -- 若使用拉普拉斯修正,给出可能类别数
            returns:
            y -- 预测结果
            """
            y = []
            if L:
                N = kwargs['N']
                up = 1
            else:
                N = 0
                up = 0
    
            for i in range(np.size(X, 0)):
                label = None
                P = -1
                # 计算每个标签的概率P(yi)
                for yi in self.attrs['label']:
                    myi = self.my_dic[yi]
                    pyi = (myi + up) / (self.m + N)
                    Pi = pyi
                    # 计算P(xi|yi)
                    for j in range(np.size(X, 1)):
                        attr_value = X[i, j]
                        # 获取该列对应的属性名
                        attr_name = [k for k, v in self.attr_idx.items() if v==j][0]
                        # 离散值
                        if self.attr_type[j] == 1:
                            # 属性值在训练集中出现
                            if attr_value in self.attrs[attr_name]:
                                pxiy = (self.mxiy_dic[yi][attr_name][attr_value] + up) / (myi + N)
                            # 属性值在训练集中没出现
                            else:
                                pxiy = up / N
                        # 连续值
                        else:
                            var = self.mxiy_dic[yi][attr_name][0]
                            mean = self.mxiy_dic[yi][attr_name][1]
                            pxiy = 1 / np.sqrt(2*np.pi*var) * np.exp(-(float(attr_value)-mean)**2 / (2*var))
                        Pi *= pxiy
                    if Pi > P:
                        P = Pi
                        label = yi
                y.append(label)
                
            return np.array(y)
    
        def lazy_predict(self, train_data, predict_X, attr_type, L, **kwargs):
            """
            懒惰学习预测
            args:
            train_data -- 输入的训练集数据矩阵, shape=(samples+1, features+1), dtype='<U?', 其中,第一行为属性,最后一列为标签
            predict_X -- 要预测的测试集数据, shape=(samples, features)
            attr_type -- 属性离散或连续的标记列表,1为离散,0为连续
            L -- 是否使用拉普拉斯修正
            N -- 若使用拉普拉斯修正,给出可能类别数
            returns:
            y -- 预测结果
            """
            attr_name = train_data[0, :-1]
            X = train_data[1:, :-1]
            y = train_data[1:, -1]
            y_value = sorted(set(y))
    
            predict_y = []
            if L:
                N = kwargs['N']
                up = 1
            else:
                N = 0
                up = 0
    
            for i in range(np.size(predict_X, 0)):
                label = None
                P = -1
                # 每个标签取值的概率
                for yi in y_value:
                    myi = np.sum(y==yi)
                    pyi = (myi + up) / (np.size(y) + N)
                    Pi = pyi
                    for j in range(np.size(X, 1)):
                        attr_value = predict_X[i, j]
                        # 离散属性
                        if attr_type[j] == 1:
                            mxi = np.sum(X[np.where(y==yi), j] == attr_value)
                            pxiy = (mxi + up) / (myi + N)
                        # 连续属性
                        else:
                            mean = np.mean(X[np.where(y==yi), j].astype('float'))
                            var = np.var(X[np.where(y==yi), j].astype('float'), ddof=1)
                            pxiy = 1 / np.sqrt(2*np.pi*var) * np.exp(-(float(attr_value)-mean)**2 / (2*var))
                        Pi *= pxiy
                    if Pi > P:
                        P = Pi
                        label = yi    
                predict_y.append(label)
    
            return np.array(predict_y)
                
    
    if __name__ == "__main__":
        pass
    

    1.2 执行脚本:

    import numpy as np
    from navie_bayes import naiveBayes
    
    f = open('watermelon.csv')
    raw_datas = f.read()
    f.close()
    
    datas = [[]]
    for data in raw_datas.split('\n'):
        datas.append(data.split(','))
    attr_name = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖量', 'label']
    datas[0] = attr_name
    
    datas = np.array(datas)
    
    test_X = np.array([['浅白','蜷缩','浊响','模糊','平坦','软粘','0.343','0.099'],
                       ['青绿','蜷缩','浊响','清晰','凹陷','硬滑','0.697','0.460']])
    
    # 指定属性类型
    attr_type = [1, 1, 1, 1, 1, 1, 0, 0]
    
    # 查表式拟合预测
    nbClassfier = naiveBayes()
    nbClassfier.fit(datas, attr_type)
    predict_y = nbClassfier.predict(test_X, L=True, N=2)
    print(predict_y)
    
    # 懒惰学习
    lazy_predict_y = nbClassfier.lazy_predict(datas, test_X, attr_type, True, N=2)
    print(lazy_predict_y)
    

    2. 结果

    对两个测试样本的预测结果为:
    在这里插入图片描述
    查表式的学习和懒惰学习均将第一个测试样本判断为坏瓜,将第二个判断为好瓜,我们通过调试看看查表式学习中生成的样本数量查询表(以字典格式存储):
    标签数量查询表:
    在这里插入图片描述
    当标签为’否’的条件下,各个属性下每个属性值的数量:
    在这里插入图片描述
    当标签为’是’的条件下,各个属性下每个属性值的数量:
    在这里插入图片描述
    其中,密度和含糖量这两个键的值为列表,列表的第一和第二项是指定标签条件下样本的方差数据和均值数据

    展开全文
  • 朴素贝叶斯分类器使用的特征模型做出了很强的独立性假设。这意味着一个类的特定特征的存在与其他所有特征的存在是独立的或无关的。 独立事件的定义: 两个事件 E 和 F 是独立的,如果 E 和 F 都有正概率并且如果 P...
  • 本文介绍如何使用Python实现一个简易的朴素贝叶斯分类器(Naive Baves classifier)。贝叶斯公式我们先简单回顾一下贝叶斯公式:其中,我们称P(A)和P(B)为先验概率,P(A|B)和P(B|A)为后验概率。上诉公式可以直接从条件...
  • 朴素贝叶斯分类器python实现

    千次阅读 2019-04-24 18:41:57
    贝叶斯公式概率论的一些基本知识: 条件概率:P(A|B)P(A|B) 联合概率:P(AB)=P(B)∗P(A|B)=P(A)∗P(B|A)P(AB)=P(B)*P(A|B)=P(A)*P(B|A) 从而导出贝叶斯式:P(A|B)=P(AB)|P(B)=P(A)∗P(B|A)/P(B)P(A|B)=P(AB)|P...
  • 高斯朴素贝叶斯分类器是针对特征值连续的情况下给出的一种分类方法。 贝叶斯公式 所有的贝叶斯分类器的基石都是概率论中的贝叶斯公式,给定训练数据集D={xi,Ci},i=1,...,N,xi∈RD,Ci∈1,...,KD=\{x_i,C_i\},i=1,...,...
  • 目录前置知识1、概念2、算法原理2.1、条件概率朴素贝叶斯分类算法1、构建数据集2、分类概率3、条件概率4、先验概率 前置知识 1、概念 上一片我们讲到的决策树算法,是反映了一种非常明确、固定的判断选择过程,即某...
  • 试编程实现拉普拉斯修正的朴素贝叶斯分类器和半朴素贝叶斯分类器中的AODE分类器,并以⻄瓜数据集3.0为训练集,对P.151“测1”样本进⾏判别。 数据集 编号 色泽 根蒂 敲声 纹理 脐部 触感 密度 含糖率 好瓜 0 1 青绿 ...
  • 一、朴素贝叶斯分类器的原理朴素贝叶斯方法是基于贝叶斯公式与特征条件独立的假设的分类方法。对于给定的训练数据集,基于特征条件独立的假设学习输入输出的联合概率分布,这样就学到了一个生成模型,然后基于该模型...
  • 朴素贝叶斯算法步骤:贝叶斯估计代码:# -*- coding:utf-8 -*-# naive Bayes 朴素贝叶斯法#author:Tomator"""算法参考与李航博士《统计学习方法》采用贝叶斯估计(拉普拉斯平滑)计算先验概率和条件概率"""from ...
  • 机器学习 --- 朴素贝叶斯分类器 python

    千次阅读 多人点赞 2020-10-22 21:07:42
    本实训项目的主要内容是基于 Python 语言搭建朴素贝叶斯分类器,并使用sklearn 实现新闻文本进行主题分类的功能。 朴素贝叶斯分类算法流程 import numpy as np class NaiveBayesClassifier(ob
  • 朴素贝叶斯算法实现的邮件分类器,其中包括代码和数据。文章链接为:https://blog.csdn.net/J__Max/article/details/82965180
  • 核心思想: 根据训练数据获取模型的后验概率,对应后验概率越大的类即预测类。 算法简介: 模型: 先验概率:p(y=Ck)p(y=Ck) p(y=C_{k}) ...朴素的含义:输入向量x的各个维度间是相互独立的,...
  • 压缩包中包括python脚本和一个PPT。 在UtralEdit中打开这两个脚本NBayes_lib.py和NBayes_...PPT详解了朴素贝叶斯算法的原理以及这个文本分类器的程序思想和运行结果详解,希望对你能够有帮助,如果有任何问题,请留言!

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,192
精华内容 4,476
关键字:

朴素贝叶斯分类器python