贝叶斯分类器含义

贝叶斯分类器是一种基于贝叶斯概率的模型,属于生成式分类器算法,用来处理分类问题.最常见的是朴素贝叶斯分类器和高斯贝叶斯分类器,"朴素"是因为它假设各个预测变量之间相互独立,"高斯"是因为它假设每类数据的每个预测变量都服从参数独立的高斯分布,也就是正态分布.

贝叶斯公式

贝叶斯分类器来源于贝叶斯公式,也就是条件概率公式,以离散情况为例便是$P(Y|X)=\frac{P(X|Y)*P(Y)}{P(X)}$.现实中便是用

$\forall Y_k \in Y, \vec{x} = (X_{1,j_1},X_{2,j_2},...,X_{d,j_d} \in X)$,其中$X_{i,j}$就是第i个预测变量的第j种情况.

的频数逼近条件概率$P(X|Y) $来计算出现了$\vec{x}$特征属于$Y_k$类的概率.

朴素贝叶斯(离散型,NB)

对于最简单的朴素贝叶斯分类器,不妨假设共有两个预测变量X1和X2,那么"朴素贝叶斯"便是 $P(y|x1,x2)=\frac{P(x1,x2|y)*P(y)}{P(x1,x2)}=\frac{P(x1|x2,y)*P(x2|y)*P(y)}{P(x1|x2)*P(x2)}=\frac{P(x1|y)*P(x2|y)*P(y)}{P(x1)*P(x2)}$

其中x1,x2分别为X1,X2两个预测变量的一个实例,y为Y的一个实例. 这样,给定X1和X2变量的值x1,x2就可以得到$P(y|x1,x2), \forall y, y\in Y$.我们既可以得到某一数据点属于各种类的概率,也可以求出$ \arg \max \limits_y P(y|x1,x2)$,也就是使得概率最大的那个类.

高斯贝叶斯(连续型,GNB)

除了离散数据,贝叶斯分类器也可以处理连续型数据,叫做"高斯贝叶斯分类器".高斯贝叶斯分类器同样基于变量之间相互独立的假设,并且假设每类数据的每个预测变量都服从高斯分布,也就是正态分布.对于每一个i,k,我们求出$\mu_{i,k}$和$\sigma_{i,k}$,还是假设我们只有两个预测变量,

那么 $P(Y_k|X_1,X_2)=\frac{P(X_1|Y_k)*P(X_2|Y_k)*P(Y_k)}{P(X_1)*P(X_2)}$ 其中 $P(X_1|Y_k) = \frac{\exp(\frac{ (X_1 - \mu_{1,k} )^2}{\sigma_{1,k}})}{\sqrt{2* \pi}*\sigma_{1,k}}$ $P(X_2|Y_k)=\frac{\exp(\frac{ (X_2 - \mu_{2,k})^2}{\sigma_{2,k}})}{\sqrt{2* \pi}*\sigma_{2,k}}$

操作中我们也会假设$\sigma_{i,k}$与k无关,也就是$P(X_i|Y_k) \sim N(\mu_{i,k}, \sigma_i)$.

算法步骤

我们可以从上面看出,朴素贝叶斯分类器需要的就是算出 $P(x|y) \forall x=(X_{1,j_1},X_{2,j_2},...,X_{d,j_d} \in X, \forall Y_k \in Y$,我们根据各个特征出现的频率就可以得到.

高斯贝叶斯分类器需要算出$\mu,\sigma \forall x \in X, \forall Y_k \in Y$.我们将最大似然估计公式对数化就知道,对于$Y_k$类,$X_1$预测变量,$\mu = mean(S), \sigma = std(S)$,其中S为属于$Y_k$类的所有样本的$X_1$预测变量的值的集合.

复杂度和收敛性

对于离散型,我们针对每一个预测变量的各种情况和每一类算出概率即可,$P(X_i = X_{i,j}|Y = Y_k)$,所以复杂度是$O(N*K*\sum\limits_{i=1}^d{|Xi|})$,其中N是样本数量,K是类的数量,d为预测变量的个数,|Xi|是Xi预测变量的可能情况的个数.

对于连续型,我们只要针对每一个预测变量和每一类算出$\mu_{ijk},\sigma_{i,j,k}$就好,所以复杂度是$O(N*K*d))$.

这里算法的收敛性是收敛于参数渐进值(当样本集无限大时的参数值)时需要的样例数,Ng&Jordan证明GNB只需要$O(logd)$个样例.

优缺点

朴素(高斯)贝叶斯分类器简单却有效,在选取合适的预测变量的条件下,在很多应用领域,比如文本类型识别和医疗判断,都表现不错.预测变量之间互不影响,所以不会因为变量的增加而造成复杂度上的爆炸.

但是在离散情况下,有oov(Out Of Vocabulary)问题,也就是面对新特征时手足无措.比如在样本中没有$X_{i,j},Y_k$的样例,那么对于出现$X_{i,j}$特征的数据点,分类器就不会把它归于$Y_k$类.所以有一些smoothing方法,比如$\forall i,j,k$,我们增加一个$X = X_{i,j},Y =Y_k$的样例.

此外,它的独立性假设条件太强,往往不合实际,每个预测变量都能对效果产生独立的影响,很依赖预测变量的选取.在小样本数据集上,GNB的预测效果也往往不如逻辑回归等其他分类器.

与其他算法的关系

离散和连续型的朴素贝叶斯分类的参数可以组合成为逻辑回归的参数,在独立性假设满足并且有无限多样例时,和逻辑回归收敛于同一个分类器.(https://www.cs.cmu.edu/~tom/mlbook/NBayesLogReg.pdf)

应用sklearn中的相关接口

sklearn中提供了3种朴素贝叶斯分类器接口:

  • naive_bayes.MultinomialNB([alpha, …])多项式模型朴素贝叶斯分类器

    处理离散数据

  • naive_bayes.BernoulliNB([alpha, binarize, …])多元伯努利模型朴素贝叶斯分类器

    类似multinomialnb,这个分类器适用于离散数据.不同之处在于,当multinomialnb与出现次数一起工作时,bernoullinb是针对二进制/布尔特征而设计的

  • naive_bayes.GaussianNB([priors])高斯贝叶斯

    处理连续型特征

例:为Car Evaluation Data Set数据集分类

这个数据集也算是比较经典的数据集了,特征都是离散数据,标签有3类,我们把它下载下来稍做处理后作为训练数据,然后进行分析


In [1]:
import requests
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report

数据获取


In [2]:
csv_content = requests.get("http://archive.ics.uci.edu/ml/machine-learning-databases/car/car.data").text

In [3]:
row_name = ['buying','maint','doors','persons','lug_boot','safety','label']

In [4]:
csv_list = csv_content.strip().split("\n")

In [5]:
row_matrix = [line.strip().split(",") for line in csv_list]

In [6]:
dataset = pd.DataFrame(row_matrix,columns=row_name)

In [7]:
dataset[:10]


Out[7]:
buying maint doors persons lug_boot safety label
0 vhigh vhigh 2 2 small low unacc
1 vhigh vhigh 2 2 small med unacc
2 vhigh vhigh 2 2 small high unacc
3 vhigh vhigh 2 2 med low unacc
4 vhigh vhigh 2 2 med med unacc
5 vhigh vhigh 2 2 med high unacc
6 vhigh vhigh 2 2 big low unacc
7 vhigh vhigh 2 2 big med unacc
8 vhigh vhigh 2 2 big high unacc
9 vhigh vhigh 2 4 small low unacc

数据预处理

由于特征和标签都是标签类别数据,因此需要为其编码,将其转化为由int类型表示类别的形式才能参与模型训练.


In [8]:
encs = {}
for i in row_name:
    enc = LabelEncoder()
    enc.fit(dataset[i])
    dataset[i] = enc.transform(dataset[i]) 
    encs[i]=enc

In [9]:
dataset[:10]


Out[9]:
buying maint doors persons lug_boot safety label
0 3 3 0 0 2 1 2
1 3 3 0 0 2 2 2
2 3 3 0 0 2 0 2
3 3 3 0 0 1 1 2
4 3 3 0 0 1 2 2
5 3 3 0 0 1 0 2
6 3 3 0 0 0 1 2
7 3 3 0 0 0 2 2
8 3 3 0 0 0 0 2
9 3 3 0 1 2 1 2

In [10]:
dataset.groupby("label").count()


Out[10]:
buying maint doors persons lug_boot safety
label
0 384 384 384 384 384 384
1 69 69 69 69 69 69
2 1210 1210 1210 1210 1210 1210
3 65 65 65 65 65 65

数据集拆分


In [11]:
train_set,validation_set = train_test_split(dataset)

In [12]:
train_set.groupby("label").count()


Out[12]:
buying maint doors persons lug_boot safety
label
0 294 294 294 294 294 294
1 55 55 55 55 55 55
2 895 895 895 895 895 895
3 52 52 52 52 52 52

In [13]:
validation_set.groupby("label").count()


Out[13]:
buying maint doors persons lug_boot safety
label
0 90 90 90 90 90 90
1 14 14 14 14 14 14
2 315 315 315 315 315 315
3 13 13 13 13 13 13

训练模型


In [14]:
nb = MultinomialNB()

In [15]:
nb.fit(train_set[['buying','maint','doors','persons','lug_boot','safety']],train_set["label"])


Out[15]:
MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)

In [16]:
pre = nb.predict(validation_set[['buying','maint','doors','persons','lug_boot','safety']])

模型评估


In [17]:
print(classification_report(validation_set["label"],pre))


             precision    recall  f1-score   support

          0       0.33      0.02      0.04        90
          1       0.00      0.00      0.00        14
          2       0.73      0.99      0.84       315
          3       0.00      0.00      0.00        13

avg / total       0.60      0.73      0.62       432

C:\Users\87\Anaconda3\lib\site-packages\sklearn\metrics\classification.py:1113: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples.
  'precision', 'predicted', average, warn_for)

由于训练数据很不平衡,模型效果其实挺差的,针对数据不平衡其实可以做很多事情以改进.如何改进不妨留给有兴趣的人来继续.