专栏名称: Python爱好者社区
人生苦短,我用Python。分享Python相关的技术文章、工具资源、精选课程、视频教程、热点资讯、学习资料等。每天自动更新和推送。
目录
相关文章推荐
Python爱好者社区  ·  蚂蚁集团发布全员信:薪资大调整。 ·  19 小时前  
Python爱好者社区  ·  字节程序员过年回家被亲戚鄙视:你985在互联 ... ·  2 天前  
Python爱好者社区  ·  无人报考!顶尖大学,校区关停 ·  昨天  
Python开发者  ·  自己编写作弊软件骗过大厂!00后拿4个顶级o ... ·  2 天前  
Python中文社区  ·  稳住别慌!用这个量化策略控制回撤,收益逆天! ·  3 天前  
51好读  ›  专栏  ›  Python爱好者社区

自我代码提升之朴素贝叶斯

Python爱好者社区  · 公众号  · Python  · 2017-09-13 17:06

正文

作者:数据取经团——JQstyle

数据取经团(公众号:zlx19930503)

专注R、Python数据分析挖掘、可视化、机器学习

(本文阅读时长:10分钟)

朴素贝叶斯的简介

在机器学习的分类算法的各个门类中,贝叶斯分类方法是一个比较重要的组成部分。而隶属于贝叶斯分类方法的算法,均是以贝叶斯定理为基础的。

对于一个分类问题,目标是Y{y1,y2…yN},已知条件X{x1,x2…xN},需要通过用X来推断出Y。在贝叶斯定理的思想下,预测目标y是否属于某一类ck,我们需要计算出相应的概率P(y=ck|x),进而判断Y的类别。通过贝叶斯公式,可以通过下式求得:

通过给定的训练数据集合,我们可以直接计算出P(y=ci)和单个变量x的条件(后验)概率P(xi|y=ci) ,需要知道P(x|y=c),还得计算出后验概率P(x|y=ci),我们还需要一个假设:

即条件独立性假设,这便是朴素贝叶斯算法的核心(即为什么“朴素”)。条件独立性假设使得各个特征属性之间彼此相互独立,因此只要将各个特征在给定类别ci的后验概率相乘就可以估算出当前各个特征取值的后验概率P(y=ci|x)。这是一个很强的假设(现实中往往很难成立)。

下面给出二分类朴素贝叶斯的训练和预测流程:
对于输入的X和Y

1.计算出先验概率:

2.计算出每一个特征各个取值的后验(条件)概率:

3.对于给定的新的数据,按照条件独立性假设和贝叶斯公式求得y所属各个类别的概率,按照概率大小决定分类结果:

改进:拉普拉斯平滑

由于朴素贝叶斯建模过程中,对于每一条特征在y的条件下后验概率的计算时,若训练集的某个特征取值在当前类别中未出现,则其后验概率为0,这样将会导致在预测中该特征在取到当前值的时候概率为0(无论其他特征如何),可能会严重影响模型的预测。因此在通常情况下,我们会在单特征各取值的后验概率公式的分子适当加一个数值,来避免概率值为0的情况:

当l为1时,则称之为拉普拉斯平滑法。

朴素贝叶斯的特点

作为比较简单的分类器之一,朴素贝叶斯有着自己的特点。其优势在于:首先,朴素贝叶斯源于古典数学的理论基础,有着稳定的分类效率;然后,朴素贝叶斯算法对小规模的数据表现很好,且可以处理多分类任务,适合增量式训练,即使数据量超出内存时,我们可以一批批的去增量训练;其次,朴素贝叶斯模型对缺失数据不太敏感,算法也比较简单,常用于文本分类(如垃圾邮件区分)。

同时,朴素贝叶斯模型的缺陷也很明显:第一,理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型假设属性之间相互独立,但这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果较差;第二,建模过程中需要知道先验概率,而先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳;第三,由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率。

代码的实现过程

导入包和数据

接下来,我们同样采用Python去实现简单的朴素贝叶斯分类器。首先加载相应的模块,并且导入数据。numpy用于建模计算,pandas仅用于导入数据。本文所用的数据依旧是马疝病的分类数据集

import numpy as npimport pandas as pd #用于加载数据集
horse = pd.read_table(u'.../horseColicTraining.txt',                  sep='\t',names=['x' + str(i) for i in range(21)]+['y']) horse_t = pd.read_table(u'.../horseColicTest.txt',                  sep='\t',names=['x' + str(i) for i in range(21)]+['y'])

连续型变量离散化

通常,朴素贝叶斯只能直接处理离散型(类别)变量(也可以假定变量的分布来进行概率推测,本文不涉及这一方面内容),所以对于那些连续(数值)变量需要首先离散化处理,建立一个分箱器,对数据集中连续型变量进行分箱。

#分箱器
def bin_get(x,your_bins):    new_x = x.copy()    
   for i in range(your_bins.shape[0]):        
       if i==0:            new_x[x<=your_bins[i]]=0        if i>0:            new_x[(x>your_bins[i-1])&(x<=your_bins[i])]=i        
       if i==your_bins.shape[0]-1:            new_x[x>your_bins[i]]=(i+1)
   return new_x

在分箱过程中,以0.2,0.4,0.6,0.8四个分位数为截点,分为5箱。若数据集unique值类别较少,则视为离散变量,不做处理。并且将分箱以后的DataFrame转换为numpy矩阵形式。

#分箱
horse_bin = horse.copy() horse_t_bin = horse_t.copy()
for i in range(horse.shape[1]-1):
   if len(set(horse_bin.ix[:,i])) > 7:#只对拥有7个unique值以上的变量进行分箱工作        horse_bin.iloc[:,i] = bin_get(horse.ix[:,i],                      np.array(horse.ix[:,i].quantile([0.2,0.4,0.6,0.8])))        horse_t_bin.iloc[:,i] = bin_get(horse_t.ix[:,i],                      np.array(horse.ix[:,i].quantile([0.2,0.4,0.6,0.8])))#转化为numpy矩阵便于建模
horse_bin = np.array(horse_bin) horse_t_bin = np.array(horse_t_bin)

朴素贝叶斯模型定义

首先定义模型类,先写入先验概率计算函数、条件(后验)概率计算函数等,并考虑拉普拉斯平滑的问题:

class Naive_Bayes_JQ:
    def pri_prob_for1(self,x,lapras=0): #对先验概率的计算函数
        prob_dir1 = {}
       for i in set(x):            prob_dir1[i] = float(sum(x == i)+lapras)/(len(x)+lapras*len(set(x)))        return(prob_dir1)    def pri_prob_for2(self,x,y,lapras=0):  #先验概率的计算函数(X且Y)        prob_dir2 = {}
       for i in set(x):
           for j in set(y):                prob_dir2[(i,j)] = float(sum(y[x==i]==j)+lapras)/(len(x)+lapras*len(set(x)))
       return






请到「今天看啥」查看全文