zoukankan      html  css  js  c++  java
  • 朴素贝叶斯

        利用近邻方法,很难量化分类的置信度。而基于概率的分类方法--贝叶斯方法,不仅可以分类,还可以给出分类概率。近邻方法别称为惰性学习方法(lazy learner),当给出数据时,这些分类器只是将他们保存或者记录下来,每次对实例进行训练时,这些分类器都会遍历整个数据集,所以分类器的速度往往跟不上,贝叶斯方法称为勤快学习方法(eager learner).给定训练数据时,这些分类器立即分析数据并构建模型。当要对某个实例进行分类时,他会使用训练得到的内部模型。从而在速度上,勤快学习器优于惰性分类器。

    贝叶斯公式:

         朴素贝叶斯的思想基础是这样的:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。通俗来说,就好比这么个道理,你在街上看到一个黑人,我问你你猜这哥们哪里来的,你十有八九猜非洲。为什么呢?因为黑人中非洲人的比率最高,当然人家也可能是美洲人或亚洲人,但在没有其它可用信息下,我们会选择条件概率最大的类别,这就是朴素贝叶斯的思想基础。http://www.cnblogs.com/leoo2sk/archive/2010/09/17/naive-bayesian-classifier.html

    实例:共和党 VS 民主党,根据两个党派投票记录来预测是哪个党派

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # __author__ : '小糖果'
    
    import os
    import pprint
    
    class BayesClassfier(object):
    
        def __init__(self,fp):
            self.acc = 0.0
            self.data = []
            for i in range(1,11):
                with open(os.path.join(fp,'hv-%02i'%i),'r') as f:
                    for line in f:
                        self.data.append(line.split())
    
            # 开始计数
            self.conditional = {}
            self.prior = {}
            for d in self.data:
                self.prior.setdefault(d[0],0.0)
                self.prior[d[0]] += 1
                self.conditional.setdefault(d[0],{})
                for key in range(16):
                    self.conditional[d[0]].setdefault(key,{})
                    self.conditional[d[0]][key].setdefault(d[key+1],0.0)
                    self.conditional[d[0]][key][d[key+1]] += 1
    
             # 求先验概率
            tolP = sum(self.prior.values())
            for key in self.prior:
                self.prior[key] /= tolP
    
            # 求条件概率
            for key1 in self.conditional:
                for key2 in self.conditional[key1]:
                    tols = sum(self.conditional[key1][key2].values())
                    for key3 in self.conditional[key1][key2]:
                        self.conditional[key1][key2][key3] /= tols
    
        def predict_classfy(self,d):
            labels = {}
            for label in self.conditional:
                labels.setdefault(label,1.0)
                for key in self.conditional[label]:
                    labels[label] *= self.conditional[label][key][d[key]]
                labels[label] *= self.prior[label]
    
            maxP = max(labels.values())
            for label,p in labels.items():
                if maxP == p:
                    return label
    
        def accurcy(self):
            for d in self.data:
                if d[0] == self.predict_classfy(d[1:]):
                    self.acc += 1
            self.acc /= len(self.data)
    
    def test():
        fp = r'C:UsersTDDesktopdataDataMiningch6house-votes'
        instances = BayesClassfier(fp)
        instances.accurcy()
        print instances.acc
    
    if __name__ == '__main__':
        test()
    

    概率估计问题

          朴素贝叶斯中的概率是真实概率的估计值。当某个事件发生概率很小时,可能在所选取的样本中发生个体为0.这时候基于频率的概率估计就会出现0概率,他会主导贝叶斯的计算过程,不管其它值是什么都无济于事。问题解决办法如下:

     

    其中m是一个称为等效的样本容量,有很多中确定m的方法,例如可以设定m为属性的个数,p设定为1/属性个数。这样处理可以避免概率为0带来的影响。

    属性问题

       朴素贝叶斯可以运用于非数值属性,也可以用于数值属性,那么上面的例子就是应用于非数值型的。对于贝叶斯方法,我们做的是计数,如果对于一些连续数值的属性,如何使用贝叶斯?方法一可以构建类别,比如讲年龄分为18<,18-22,23-30,30-40,>40等不同档次,这样就将数值信息转换为离散值,就可以像前面一样使用贝叶斯。方法二是使用高斯分布,高斯分布即为正态分布,我们假设了属性值满足高斯分布,然后利用概率,高斯分布的密度函数来计算概率。可用如下公式如下:

      

    下面是印第安人的糖尿病数据。将实体数据按高斯分布来计算概率,然后使用朴素贝叶斯分类:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # __author__ : '小糖果'
    
    import os
    import numpy as np
    import pprint
    
    class BayesClassfier(object):
    
        def __init__(self, fp, testBucket):
    
            self.test = []
            with open(os.path.join(fp,'pima-%02i'%testBucket),'r') as f:
                for line in f:
                    self.test.append(line.split())
    
            self.prior = {}
            self.numericValues = {}
    
            # 统计训练样本的信息
            for i in range(1,11):
                if i != testBucket:
                    with open(os.path.join(fp, 'pima-%02i' % i),'r') as f:
                        for line in f:
                            d = line.split()
                            self.prior.setdefault(d[-1],0.0)
                            self.prior[d[-1]] += 1
                            self.numericValues.setdefault(d[-1],{})
                            for k in range(8):
                                self.numericValues[d[-1]].setdefault(k,[])
                                self.numericValues[d[-1]][k].append(float(d[k]))
            # 计算先验概率
            tols = sum(self.prior.values())
            for k in self.prior:
                self.prior[k] /= tols
    
            # 计算中位数和标准差
            self.mean = {}
            self.std = {}
            for k,v in self.numericValues.items():
                self.mean.setdefault(k,{})
                self.std.setdefault(k,{})
                for k1,v1 in v.items():
                    self.std[k][k1] = np.std(v1)
                    self.mean[k][k1] = np.mean(v1)
    
        def pdf(self,m,s,x):
            return 1./(np.sqrt(np.pi*2)*s)*np.exp(-((x-m)**2)/(2*(s**2)))
    
        def get_class(self,d):
            labels = {}
            for label in self.prior:
                labels.setdefault(label,1.0)
                for k in range(8):
                    labels[label] *= self.pdf(self.mean[label][k],
                                              self.std[label][k],
                                              float(d[k]))
                labels[label] *= self.prior[label]
    
            maxP = max(labels.values())
            for k,v in labels.items():
                if maxP == v:
                    return k
    
        def crossVaild(self):
            acc = 0
            for d in self.test:
                if self.get_class(d[:-1]) == d[-1]:
                    acc += 1
            return acc*1./len(self.test)
    
    
    def test():
        fp = r'C:UsersTDDesktopdataDataMiningch6pima'
        acc = 0.0
        for testBucket in range(1,11):
            instance = BayesClassfier(fp,testBucket)
            acc += instance.crossVaild()
        acc /= 10
        print acc
    if __name__ =='__main__':
        test()
    

    正确率77.33%

    贝叶斯于Knn的比较

    贝叶斯的优点: 

         1 实现简单,只是简单的计数问题

         2 和其他方法比,需要训练的数据少

    贝叶斯主要确点:贝叶斯不能学习到特征的相互联系。

    Knn主要优点:

         1 实现简单

         2 不用假设数据具有特定的结构

    Knn 主要缺点: 需要大量的内存来存取数据

    朴素贝叶斯中“朴素”的含义:贝叶斯的的工作有效需要特征间相互独立,但是大部分实际问题都不满足这一条件,我们只是假设他们间相互独立,之所以叫做朴素贝叶斯是因为我们知道知道特征间可能存在不独立,但是我们仍然假设他们独立。事实说明,尽管朴素的假设存在,贝叶斯的效果依然不错。

  • 相关阅读:
    Java 过滤器
    理解Java中的弱引用(Weak Reference)
    AOP编程
    利用ThreadLocal管理事务
    Redis设计与实现-附加功能
    Redis设计与实现-主从、哨兵与集群
    Redis设计与实现-客户端服务端与事件
    Redis设计与实现-持久化篇
    Redis设计与实现-内部数据结构篇
    重温软件架构设计-程序员向架构师转型必备
  • 原文地址:https://www.cnblogs.com/td15980891505/p/6070494.html
Copyright © 2011-2022 走看看