贝叶斯分类器

贝叶斯分类器

1.基础知识

概率论的基本知识
先验概率:由以往的数据得到的
后验概率:得到信息后再重新加以修正的概率         

条件风险公式(期望损失):

R(cix)=j=1NλijP(cjx) R ( c i ∣ x ) = ∑ j = 1 N λ i j P ( c j ∣ x )

其中,基于后验概率 P(cix) P ( c i ∣ x ) 可获得将样本x分类为 ci c i 所产生的期望损失(expected loss)

λij λ i j 是将一个真实标记为 cj c j 的样本误分类为 ci c i 所产生的损失

对于每个样本 x x 选择能使后验概率 P(cx) P ( c ∣ x ) 最大的类别标记

基于贝叶斯定理, P(cx) P ( c ∣ x ) 可以写成:

P(cx)=P(x,c)P(x)=P(c)P(xc)P(x) P ( c ∣ x ) = P ( x , c ) P ( x ) = P ( c ) P ( x ∣ c ) P ( x )

先对联合概率分布 P(x,c) P ( x , c ) 进行建模,再求后验概率

判别式模型&生成式模型

判别式模型(discriminative models):

给定X,可以通过直接建模 P(cx) P ( c ∣ x ) 来预测c,简单而又直接的办法.例如:决策树,神经网络,支持向量机都是判别式模型的范畴.

生成式模型(generative models):

先对联合概率分布 P(x,c) P ( x , c ) 建模,然后再由此获得 P(cx) P ( c ∣ x ) .典型的就是贝叶斯函数定理

后验概率的最大化

对于类先验概率(prior), P(c) P ( c ) ,是样本空间中各类样本所占的比例,根据大数定律,当样本足够充足且独立同分布时,可以用样本出现的频率来拟合概率.

类条件概率 P(xc) P ( x ∣ c )  可能会出现属性组合爆炸的情况,一般不能使用简单的频率估计.(对于简单的朴素贝叶斯分类器,是可以直接使用频率来表达概率)

注意区分 “未被观测到”和”出现概率为零”

极大似然估计

Dc D c 表示训练集 D D 中第c类样本组成的集合,假设这些样本独立同分布.则参数 θc θ c 对于数据集 Dc D c 的似然是:

P(Dcθc)=P(xθc) P ( D c ∣ θ c ) = ∏ P ( x ∣ θ c )

解决实际问题时,还需要考虑,连乘操作会导致数值的下溢 可以考虑使用对数似然方程 ddθInL(θ)=0 d d θ I n L ( θ ) = 0 的方法:

LL(θc)=logP(Dcθc) L L ( θ c ) = log ⁡ P ( D c ∣ θ c )

=xDclogP(xθc) = ∑ x ∈ D c log ⁡ P ( x ∣ θ c )

朴素贝叶斯分类器

属性条件独立性假设(attribute conditional independence assumption):

属性之间相互独立,基于这个假设,可以重新得到公式

P(cx)=P(c)P(xc)P(x)=P(c)P(x)i=1dP(xic) P ( c ∣ x ) = P ( c ) P ( x ∣ c ) P ( x ) = P ( c ) P ( x ) ∏ i = 1 d P ( x i ∣ c )

其中d 是属性的数目, xi x i x x 在第i个属性上的取值

朴素分类器的训练过程就是基于训练数据集D来估计类先验概率 P(c) P ( c ) ,并为每个属性估计条件概率 P(xic) P ( x i ∣ c )

半朴素贝叶斯分类器(semi-naive bayes classifiers)

朴素贝叶斯假设各个属性之间相互独立,但这一点在实际过程中很难实现,尝试对属性条件独立性假设进行一定程度的放松.

假设每个属性在类别之外最多依赖于一个其他属性.

贝叶斯网

借助有向无环图来实现属性之间的依赖关系. B=G,Θ B = ⟨ G , Θ ⟩

其中G是一个有向无环图

参数 Θ Θ 定量描述这种依赖关系, Θ Θ 包含了每个属性的条件概率表 θxiπi=PB(xiπi) θ x i ∣ π i = P B ( x i ∣ π i )

有向图转换为道德图
参考:<机器学习> 周志华 清华大学出版社

最小描述长度情况下的评分函数:

s(BD)=f(θ)BLL(BD) s ( B ∣ D ) = f ( θ ) ∣ B ∣ − L L ( B ∣ D )

2.思想脉络

基于生成式模型,利用贝叶斯公式将求解进行转换.

训练数据集D,来估计类先验概率 P(c) P ( c ) ,并为每个属性估计出条件概率 P(xic) P ( x i ∣ c )

思想脉络==算法推导.主要还是算法的推导过程.

3.算法推导

训练过程

1.类先验概率 P(c) P ( c ) :

Dc D c 表示训练集D中第c类样本组成的集合

P(c)=DCD P ( c ) = ∣ D C ∣ ∣ D ∣

2.类条件概率 P(xic) P ( x i ∣ c ) :

2.1对于离散属性而言: Dc,xi D c , x i 表示 Dc D c 在i个属性上取值为 xi x i 样本集合
则条件概率为:

P(xic)=Dc,xiDc P ( x i ∣ c ) = ∣ D c , x i ∣ ∣ D c ∣

2.2对于连续属性考虑概率密度函数. 假定 p(xic)N(μc,i,σ2c,i) p ( x i ∣ c ) ∼ N ( μ c , i , σ c , i 2 )
考虑均值和方差,则条件概率为:

p(xtc)=12πσc,iexp((xiμc,i)22σ2c,i) p ( x t ∣ c ) = 1 2 π σ c , i e x p ( − ( x i − μ c , i ) 2 2 σ c , i 2 )

贝叶斯判定准则

基于最小化分类错误率的贝叶斯最优分类器为:

h(x)=argmaxcyP(cx) h ( x ) ∗ = a r g max c ∈ y P ( c ∣ x )

得到的最重要的贝叶斯判定准则:

hnb(x)=argmaxcyP(c)i=1dP(Xic) h n b ( x ) = a r g max c ∈ y P ( c ) ∏ i = 1 d P ( X i ∣ c )

上述训练过程需要注意的一点是: “未被观测到”和”出现概率为零”

若某个属性值咋训练集中没有与某个类同时出现过.基于上式进行计算,会让连乘式中出现概率值为零的情况.
防止出现连乘为0的现象.

一般进行拉普拉斯修正
平滑处理:

P(c)=Dc+1D+N, P ( c ) = ∣ D c ∣ + 1 ∣ D ∣ + N ,

P(xic)=Dc,xi+1Dc+Ni. P ( x i ∣ c ) = ∣ D c , x i ∣ + 1 ∣ D c ∣ + N i .

实现拉普拉斯修正的朴素贝叶斯分类器的算术推导过程

朴素贝叶斯算法(naive bayes algorithm):

输入:训练数据集 T={ (x1,y1),(x2,y2),...,(xN,yN) ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } 其中 xi=(x1i,x2i,...,xni)T x i = ( x i 1 , x i 2 , . . . , x i n ) T , xji x i j 是i个样本的第j个特征, xji{aj1,aj2,...,ajs} x i j ⊂ { a j 1 , a j 2 , . . . , a j s } , ajl a j l 是第j个特征可能的取的第l个值;
实例 x

输出:实例 x 的分类.

(1) 计算先验概率及条件概率

P(Y=ck)=Ni=1I(yi=ck)N,k=1,2,...K P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) N , k = 1 , 2 , . . . K

p(Xj=ajiY=ck)=Ni=1I(xji=aji,yi=ck)Ni=1I(yi=ck),j=1,2,...,n;l=1,2,...,Sj;k=1,2,...,K p ( X j = a j i ∣ Y = c k ) = ∑ i = 1 N I ( x i j = a j i , y i = c k ) ∑ i = 1 N I ( y i = c k ) , j = 1 , 2 , . . . , n ; l = 1 , 2 , . . . , S j ; k = 1 , 2 , . . . , K

(2)对于给定的实例 x=(x1,x2,...,xn)T x = ( x 1 , x 2 , . . . , x n ) T ,计算:

P(Y=ck)j=1nP(Xj=xjY=ck),k=1,2,...,K P ( Y = c k ) ∏ j = 1 n P ( X j = x j ∣ Y = c k ) , k = 1 , 2 , . . . , K

(3)确定实例x的分类

y=argmaxckP(Y=ck)j=1nP(Xj=xjY=ck) y = a r g m a x c k P ( Y = c k ) ∏ j = 1 n P ( X j = x j ∣ Y = c k )

4.编程实现

上面只是算法推导的思路,然后考虑拉普拉斯修正进行编程实现

# input watermelon csv file and process easy data cleaning

import pandas as pd 
def in_put():
    """
    @ return df.data
    """
    with open("/home/dengshuo/GithubCode/ML/CH04/ID3watermelon3.csv") as f:
        df=pd.read_csv(f)
    return df
# too many thing need consider
# i need help 

两个解决的方法,一步一步编程法;或者直接调用Sklearn库中的函数来进行
一步一步编程法: 需要强大的编程能力

调用Sklearn : 可能对数据的处理要求较高,对数据量较少的结果可能不是很好

1.按步骤编程进行代码实现:

一个总结,当要去实现一个特定函数功能时候,可先将输入假设为所需要的数据结构和类型,读输入数据的处理放到后面
将每个函数进行结合.

也可以先使用一个函数,然后再去定义(在知道函数功能的前提下)

# date&time : 2018.05.07
# @author   : dengshuo

# input  excel or csv data
# define class 

class LaplacianNB():
    """
    Laplacian naive bayes for binary classification problem.
    """
    def __init__(self):
        """
        no parameter init 
        this mean a pulic init or supet init variables.
        """
    def train(self,X,y):
        """
        Training laplacian naive bayes classifier with training set(X,y)
        Input:X,list of instances
              y,list of labels
        """
        N=len(y)
        self.class=self.count_list(y)
        self.class_num=len(self.class)
        # calc prior probability
        self.class_p={}
        for c,n in self.class.items():
            self.class_p[c]=float(n+1)/(N+self.class_num)

        #print(self.class_p)

        # calc conditional probability

        self.discrete_attr_good_p=[]
        self.diacrete_attr_bad_p=[]
        for i in range(6):
            attr_with_good=[]
            attr_with_bad=[]
            for j in range(N):
                if y[j]==1:    # it can replace with : if y[i]=="是"
                    attr_with_good.append(X[j][i])
                else:
                    attr_with_bad.append(X[j][i])
            unique_with_good=self.count_list(attr_with_good)
            unique_with_bad=self.count_list(attr_with_bad)
            self.discrete_attr_good_p.append(self.discrete_p(unique_with_good,self.class[1]))
            self.discrete_attr_bad_p.append(self.discrete_p(unique_with_bad,self.class[0]))


        # calc the continuous variable conditional probability

        self.good_mus=[]
        self.good_vars=[]
        self.bad_mus=[]
        self.bad_vars=[]
        for i in range(6,8):
            attr_with_good=[]
            attr_with_bad=[]
            for j in range(N):
                if y[j]==1:
                    attr_with_good.append(X[j][i])
                else:
                    attr_with_bad.append(X[j][i])

            good_mu,good_var=self.mu_var_of_list(attr_with_good)
            bad_mu,bad_var=self.mu_var_of_list(attr_with_bad)
            self.good_mus.append(good_mu)
            self.good_vars.append(good_var)
            self.bad_mus.append(bad_mu)
            self.bad_vars.append(bad_var)

    def predict(self,x):
        """
        x:the testset need calculate
        @return: return the label class 0 or 1
        """
        p_good=self.class_p[1]
        p_bad=self.class_p[0]
        for i in range(6):
            p_good*=self.discrete_attar_with_good_p[i][x[i]]
            p_bad*=self.discrete_attr_with_good_p[i][x[i]]
        for i in range(6,8):
            p_good*=self.continuous_p([x[i]],self.good_mus[i],self.good_vars[i])
            p_bad*=self.continuous_p([x[i]],self.bad_mus[i],self.bad_vars[i])
        if p_good>=p_bad:
            return p_good,p_bad,1
        else:
            return p_good,p_bad,0




    def count_list(self,List):
        """
        List : input data
        @return :  count unique elements in list with dictionary
        """
        unique_dict={}
        for i in set(List):
            unique_dict[i]=List.count(e)
        return unique_dict

    def discrete_p(self,d,N_class):
        """
        d:attribute of dictionary
        n_class: the number of label class 
        @return:the probaility of each feature with dictionary
        """
        new_d={}
        for a,n in d.items():
            new_d[a]=float(n+1)/(N_class+len(d))   # n_class: means good or bad feature (amount)=class[1]
        return new_d

    def mu_var_of_list(self,l):
        """
        l:list of feature
        @return: 
        """
        mu=sum(l)/float(len(l))
        var=0
        for i in range(len(l)):
            var+=(l[i]-mu)**2
        var=var/float(len(l))
        return mu,var 

    def continuous_p(self,x,mu,var):
        """
        x: the input testset 
        mu: the meanvalue
        var: the variance
        @return the testset probaility
        """
        import math
        p=1.0/(math.sqrt(2*math.pi)*math.sqrt(var)*math.exp(-(x-mu)**2/(2*var)))
        return p

import xlrd

# this package often use it can read excel files

if __name__=="__main__":
    lnb=laplacianNB()

    # read excel dataset ,of course can use pandas read csv_file
    # pandas can read excel files to.
    workbook=xlrd.open_workbook('the dataset.xlsx')
    sheet=workbook.sheet_by_name("Sheet1")
    X=[]
    for i in range(17):
        x=sheet.col_values(i)
        for j in range(6):
            x[j]=int(x[j])
        x.pop()
        X.append(x)
    y=sheet.row_values(8)
    y=[int(i) for i in y]
    lnb.trian(X,y)
    label=lnb.predict([1,1,1,1,1,1,0.697,0.460])
    print("predict result {}".format(label))

调用Sklearn库来实现

数据的读取,数据的处理,(数据的可视化处理),库函数的调用

最重要,可能也是最难的就是:如何将数据处理成函数可以直接使用的类型(先不管数据的输入类型,定义函数) 数据的预处理

# read csv_file dataset
import pandas as pd 
def in_put():
    """
    @ return df.data
    """
    with open("/home/dengshuo/GithubCode/ML/CH04/ID3watermelon3.csv") as f:
        df=pd.read_csv(f)
    return df

# not fully comprehension how to cleaning df_dataset
# data,expecially cleaning df.data
# import library 
from sklearn.naive_bayes import GaussianNB
# assumed have X(predictor) and y(target) for training data 
clf=GaussianNB()
clf.fit(X,y)

print(clf.predict([[1,1,1,1,1,1,0.697,0.460]]))
# python test console

import pandas as pd
import numpy as np 
with open('/home/dengshuo/GithubCode/ML/CH06/watermelon_3a.csv') as f:
      df=pd.read_csv(f,header=None,)
with open('/home/dengshuo/GithubCode/ML/CH06/watermelon_test.csv') as p:
      df_test=pd.read_csv(p,header=None,)
#df=df.rename(columns={'编号':'numbers'})
df.columns=['id','density','sugar_index','label']
df_test.columns=['id','density','sugar_index','label']
df.set_index(['id'])
# print(df)
X=df[['density','sugar_index']].values
x_test=df_test[['density','sugar_index']].values
# this is a np.array 
y=df[['label']].values
# extract the values

# import scikit learn library
from sklearn.naive_bayes import GaussianNB 
gnb=GaussianNB()
gnb.fit(X,y)

predict=gnb.predict(x_test)
print(predict)
[1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 0]


/home/dengshuo/anaconda3/lib/python3.6/site-packages/sklearn/utils/validation.py:578: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().
  y = column_or_1d(y, warn=True)

数据太少,导致正确率不是很高

总结

推导,为什么可以用条件概率来表达 后验概率的值 重要的是公式的推导

对于朴素贝叶斯函数计算的整个流程的掌握

EM算法的学习

贝叶斯网的深度理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值