机器学习-4-朴素贝叶斯法

前言

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对给定的输入$x$,利用贝叶斯定理求出后验概率最大的输出$y$。

朴素贝叶斯法是典型的生成学习方法,生成方法由训练数据学习联合概率分布$P(X,Y)$,然后求得后验概率分布$P(Y|X)$。具体来说,利用训练数据学习$P(X|Y)$和$P(Y)$的估计,得到联合概率分布:

贝叶斯原理

朴素贝叶斯法的基本理论是贝叶斯原理。贝叶斯公式直接可以根据条件概率的定义直接推出。考虑一个问题: $P(A|B)$ 是在B发生的情况下A发生的可能性。首先,事件B发生之前,我们对事件A的发生有一个基本的概率判断,称A的先验概率,用 $P(A)$ 表示。其次,事件B发生之后,我们对事件A的发生概率重新评估,称为A的后验概率,用 $P(A|B)$ 表示。同样地定义 $P(B)$ 和 $P(B|A)$ 。
所以根据贝叶斯公式为:

根据条件概率公式,在事件B发生的情况下事件A发生的概率是

同样地,在事件A发生的条件下事件B发生的概率是

整合上述两个公式:$P(A|B)P(B)=P(B|A)P(A)$ ,上式两边同除 $P(B)$ ,若$P(B)$是非零的,我们可以直接得到贝叶斯定理的公式表达式。

朴素贝叶斯的学习与分类

设输入空间$\mathcal{X} \subseteq \mathbf{R}^n$为$n$维随机变量的集合,输出空间为类标记集合$\mathcal{Y}=\{ c_1, c_2, \cdots, c_K\}$。输入为特征向量$x \in \mathcal{X}$,输出为类标记$y \in \mathcal{Y}$。$X$是定义在输入空间$\mathcal{X}$上的随机向量,$Y$是定义在输出空间$\mathcal{Y}$上的随机变量。$P(X,Y)$是$X$和$Y$的联合概率分布。训练数据集$T=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right\}$由$P(X,Y)$独立同分布产生。

朴素贝叶斯通过训练数据集学习联合概率分布$P(X,Y)$,具体地,学习先验概率分布和条件概率分布。先验概率分布:

条件概率分布:

于是根据$P(X,Y)=P(Y)P(X|Y)$可以学习到联合概率分布。

条件概率分布$P\left(X=x | Y=c_{k}\right)$有指数级数量的参数,其估计实际是不可行的,假设$x^{(j)}$可能值有$S_j$个,$j=1,2,\cdots,n$,$Y$可取值有$K$个,那么参数为$K\prod^n_{j=1}S_j$。

朴素贝叶斯法对条件概率分布作了独立性的假设,朴素贝叶斯法也因此得名。条件独立性假设是:

朴素贝叶斯法实际上学习到生成数据的机制,所以属于生成模型。条件独立假设等于是说用于分类的特征在类确定的条件下都是条件独立的。这一假设使朴素贝叶斯法变得简单,但有时会牺牲一定的分类准确率。

朴素贝叶斯法用于分类时,对给定的输入$x$,通过学习到的模型计算后验概率分布$P\left(X=x | Y=c_{k}\right) $,将后验概率最大的类作为$x$的类的输出。后验概率计算根据贝叶斯定理进行:

将条件独立性假设代入上式:

这就是朴素贝叶斯法分类的基本公式,于是,朴素贝叶斯分类器可表示为:

上式中,分母对于所有的$c_k$都是相同的,所以,

后验概率最大化的含义

朴素贝叶斯法将实例分到后验概率最大的类中,这等价于期望风险最小化,假设选择0-1损失函数:

式中$f(X)$是分类决策函数,期望风险函数为:

期望是对联合分布$P(X,Y)$取的。由此取条件期望:

为了使期望风险最小化,只需对$X=x$逐个极小化,由此得到:

这样一来,根据期望风险最小化准则就得到了后验概率最大化准则:

即朴素贝叶斯法所采样的原理。

朴素贝叶斯法的参数估计

极大似然估计

在朴素贝叶斯法中,学习意味着估计$P(Y=c_k)$和$P(X^{(j)}=x^{(j)}|Y=c_k)$。可以应用极大似然估计法估计相应的概率。先验概率$P(Y=c_k)$的极大似然估计是

设第$j$个特征$x^{(j)}$可能取值的集合为$\{a_{j1},a_{j2},\cdots, a_{jS_j}\}$,条件概率$P(X^{(j)}=a_{jl}|Y=c_k)$的极大似然估计是

式中,$x^{(j)}$是第$i$个样本的第$j$个特征;$a_{jl}$是第$j$个特征可能取的第$l$个值;$I$为指示函数。

学习与分类算法

算法:朴素贝叶斯算法

输入:训练数据集$T=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right\}$,其中$x_i = (x^{(1)}_i,x^{(2)}_i,\cdots,x^{(n)}_i)^T$,$x^{(j)}_i$是第$i$个样本的第$j$个特征,$x^{(j)}_i \in \{a_{j1},a_{j2},\cdots, a_{jS_j}\}$,$a_{jl}$是第$j$个特征可能取的第$l$个值,$j=1,2, \cdots, n$ ,$ l=1,2, \cdots, S_{j}$, $y_i \in \{ c_1, c_2, \cdots, c_K\}$,实例$x$。

输出:实例$x$的分类。

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

(2)对于给定的实例$x = (x^{(1)},x^{(2)},\cdots,x^{(n)},、)^T$,计算

(3)确定实例$x$的类

例题

mark

贝叶斯估计

用极大似然估计可能会出现所要估计的概率值为0的情况。这时会影响到后验概率的计算结果,使分类产生偏差。解决这一问题的方法是采用贝叶斯估计。具体地,条件概率的贝叶斯估计是:

式中$\lambda \ge0$。等价于在随机变量各个取值的频数上赋予一个正数。当$\lambda=0$时就是极大似然估计。常取$\lambda=1$,这时称为拉普卡斯平滑,显然,对任何${j=1,2, \cdots, n ; l=1,2, \cdots, S_{j}, \quad k=1,2, \cdots, K}$,有

先验概率的贝叶斯估计是

例题

mark

高斯朴素贝叶斯

特征的可能性被假设为高斯。

概率密度函数:

数学期望:$\mu$

方差:$\sigma^2=\frac{\sum(X-\mu)^2}{N}$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from collections import Counter
import math

# data
def create_data():
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
data = np.array(df.iloc[:100, :])
return data[:, :-1], data[:, -1]


class NaiveBayes:
def __init__(self):
self.model = None

# 数学期望
@staticmethod
def mean(X):
return sum(X) / float(len(X))

# 标准差
def stdev(self, X):
avg = self.mean(X)
return math.sqrt(sum([pow(x - avg, 2) for x in X])) / float(len(X))

# 概率密度函数
def gaussian_probability(self, 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

# 处理X_train
def summarize(self, train_data):
summaries = [(self.mean(i), self.stdev(i)) for i in zip(*train_data)]
return summaries

# 分类别求出数学期望和方差
def fit(self, X, y):
labels = list(set(y))
data = {label: [] for label in labels}
for f, label in zip(X, y):
data[label].append(f)
self.model = {label:self.summarize(value)
for label, value in data.items()}
return "gaussianNB train done!"

# 计算概率
def calculate_probabilities(self, input_data):
probabilities = {}
for label, value in self.model.items():
probabilities[label] = 1
for i in range(len(value)):
mean, stdev = value[i]
probabilities[label] *= self.gaussian_probability(input_data[i], mean, stdev)
return probabilities

# 类别
def predict(self, X_test):
label = sorted(self.calculate_probabilities(X_test).items(),
key=lambda x: x[-1])[-1][0]
return label

def score(self, X_test, y_test):
right = 0
for X, y in zip(X_test, y_test):
label = self.predict(X)
if label == y:
right += 1
return right / float(len(X_test))



if __name__ == '__main__':
X, y = create_data()
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3)

model = NaiveBayes()
model.fit(X_train, y_train)

print(model.predict([4.4, 3.2, 1.3, 0.2]))

score = model.score(X_test, y_test)
print(score)


# sklean实现
print("==sklean==")
from sklearn.naive_bayes import GaussianNB
clf = GaussianNB()
clf.fit(X_train, y_train)
print(clf.predict([[4.4, 3.2, 1.3, 0.2]]))
print(clf.score(X_test, y_test))

参考文献
统计学习方法. 李航
https://github.com/fengdu78/lihang-code/blob/master/%E7%AC%AC04%E7%AB%A0%20%E6%9C%B4%E7%B4%A0%E8%B4%9D%E5%8F%B6%E6%96%AF/4.NaiveBayes.ipynb

Donate comment here
------------The End------------
0%