朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。本文将讲解二分类的朴素贝叶斯分类器的原理以及程序实现。
模型
已知一组有
n
n
n个样本的训练集
{
(
x
i
,
y
i
)
}
i
=
1
n
,
x
i
∈
R
t
,
y
i
∈
{
1
,
.
.
.
,
k
}
\{(x_i,y_i)\}_ {i=1}^n,x_i\in\mathbb R^t,y_i\in\{1,...,k\}
{(xi,yi)}i=1n,xi∈Rt,yi∈{1,...,k}
其中,每个输入变量
x
i
x_i
xi都有
t
t
t个特征,输出变量
y
i
y_i
yi表示类别标签值。
模型假设
1.输入变量
x
x
x和输出变量
y
y
y都假定为随机变量。
2.输入变量
x
x
x的各特征间都具有条件独立性,即任意两个特征都是独立的。
算法原理
对于一个输入样本
x
x
x,通过计算该样本属于不同类别的概率,然后将最大概率所对应的类别作为该样本的类别。首先
P
(
Y
=
c
∣
X
=
x
)
P(Y=c|X=x)
P(Y=c∣X=x)
表示在样本是
x
x
x的条件下,类别是
c
c
c的概率。之后由条件概率的公式,可以得到它等于
P
(
Y
=
c
,
X
=
x
)
P
(
X
=
x
)
=
P
(
X
=
x
∣
Y
=
c
)
P
(
Y
=
c
)
P
(
X
=
x
)
\frac{P(Y=c,X=x)}{P(X=x)}=\frac{P(X=x|Y=c)P(Y=c)}{P(X=x)}
P(X=x)P(Y=c,X=x)=P(X=x)P(X=x∣Y=c)P(Y=c)
再由全概率公式拆解等式的分母,得到
P
(
X
=
x
∣
Y
=
c
)
P
(
Y
=
c
)
∑
i
=
1
k
P
(
X
=
x
∣
Y
=
c
i
)
P
(
Y
=
c
i
)
\frac{P(X=x|Y=c)P(Y=c)}{\sum_{i=1}^kP(X=x|Y=c_i)P(Y=c_i)}
∑i=1kP(X=x∣Y=ci)P(Y=ci)P(X=x∣Y=c)P(Y=c)
然后又因为样本的各特征间具有独立性,所以等式的分子又可以化为
P
(
Y
=
c
)
∏
i
=
1
t
P
(
X
(
i
)
=
x
(
i
)
∣
Y
=
c
)
∑
i
=
1
k
P
(
X
=
x
∣
Y
=
c
i
)
P
(
Y
=
c
i
)
\frac{P(Y=c)\prod_{i=1}^t P(X^{(i)}=x^{(i)}|Y=c)}{\sum_{i=1}^kP(X=x|Y=c_i)P(Y=c_i)}
∑i=1kP(X=x∣Y=ci)P(Y=ci)P(Y=c)∏i=1tP(X(i)=x(i)∣Y=c)
最后,对于同一个样本
x
x
x,上述等式的分母计算结果都是一样的,因此可以不用计算分母,直接计算分子,然后比较概率大小,选取最大的概率所对应的类别作为样本
x
x
x的预测类别。
程序实现
训练函数fit
这个函数先计算并保存后验概率
P
(
Y
=
c
k
)
P(Y=c_k)
P(Y=ck)
和每个类别下不同特征的条件概率
P
(
X
(
i
)
=
x
(
i
)
∣
Y
=
c
j
)
P(X^{(i)}=x^{(i)}|Y=c_j)
P(X(i)=x(i)∣Y=cj)
预测函数predict
根据公式对预测样本的概率进行计算,需要注意的是,有些特征的取值并没有出现在训练样本中,这时可以用一个比较小的概率进行替代。
封装成类
class NaiveBayes:
def fit(self, X, y):
n_sample,n_feature = X.shape
# 计算P(Y=ck)的概率
self.y_set = set(y)
Py = [sum(y==label)/len(y) for label in self.y_set]
self.Py = dict(zip(self.y_set,Py))
# 计算各条件概率
self.PXY = {}
for label in self.y_set:
cur_x = X[y==label]
Sum = len(cur_x)
value = []
for i in range(n_feature):
feature = cur_x[:,i]
PXY = [sum(feature==fea)/Sum for fea in set(feature)]
PXY = dict(zip(set(feature), PXY))
value.append(PXY)
self.PXY[label] = value
def predict(self, X):
def check(x):
dic = {}
for label in self.y_set:
cur_fea = self.PXY[label]
prod = self.Py[label]
for i in range(len(x)):
# 不存在对应特征时,赋一个比较小的概率
if x[i] not in cur_fea[i]:
prod *= 0.00001
else:
prod *= cur_fea[i][x[i]]
dic[label] = prod
return sorted(dic.items(), key=lambda x:x[1], reverse=True)[0][0]
y_pred = []
for x in X:
y_pred.append(check(x))
return np.array(y_pred)
实例化
clf = NaiveBayes()
clf.fit(X, y)
clf.predict(x_test)