您的位置:首页 > 编程语言 > Python开发

机器学习之朴素贝叶斯原理及python实现

2020-06-04 08:08 309 查看

朴素贝叶斯

朴素贝叶斯法是基于贝叶斯定理于特征独立假设的一类生成算法

1. 朴素贝叶斯原理
1.1 以一个垃圾邮件分类的例子开始

有样本如下:
邮件一:x(1)=(明天,早上,参加,早会)x^{(1)} = (明天, 早上, 参加, 早会)x(1)=(明天,早上,参加,早会) 分类:y(1)=正常邮件y^{(1)}=正常邮件y(1)=正常邮件
邮件二:x(2)=(希望,明天,听到,好消息)x^{(2)} = (希望, 明天, 听到, 好消息)x(2)=(希望,明天,听到,好消息) 分类:y(2)=正常邮件y^{(2)} = 正常邮件y(2)=正常邮件
邮件三:x(3)=(欢迎,明天,订阅,购买)x^{(3)} = (欢迎, 明天, 订阅, 购买)x(3)=(欢迎,明天,订阅,购买) 分类:y(3)=垃圾邮件y^{(3)} = 垃圾邮件y(3)=垃圾邮件
邮件四 : x(4)=(听到,我们的,产品)x^{(4)} = (听到, 我们的, 产品)x(4)=(听到,我们的,产品) 分类:y(4)=垃圾邮件y^{(4)} = 垃圾邮件y(4)=垃圾邮件

如上面例子所示:
训练样本的输入数据可以表示为:X=(x(1),x(2),...,x(N))X = (x^{(1)}, x^{(2)}, ...,x^{(N)})X=(x(1),x(2),...,x(N))
训练样本的输出数据可以表示为:Y=(y(1),y(2),...,y(N))Y = (y^{(1)}, y^{(2)},..., y^{(N)})Y=(y(1),y(2),...,y(N))
其中:

x(1)=(x1(1),x2(1),...,xM1(1))x^{(1)} = (x_1^{(1)}, x_2^{(1)},...,x_{M_1}^{(1)})x(1)=(x1(1)​,x2(1)​,...,xM1​(1)​)

x(2)=(x1(2),x2(2,...,xM2(2))x^{(2)} = (x_1^{(2)}, x_2^{(2},...,x_{M_2}^{(2)})x(2)=(x1(2)​,x2(2​,...,xM2​(2)​)

x(N)=(x1(N),x2(N),...,xMN(N))x^{(N)} = (x_1^{(N)}, x_2^{(N)},...,x_{M_N}^{(N)})x(N)=(x1(N)​,x2(N)​,...,xMN​(N)​)

其中x(n)x^{(n)}x(n)代表第nnn个样本的输入数据,xmn(n)x_{m_n}^{(n)}xmn​(n)​代表第nnn个样本的第mmm个元素。

设有KKK个输出类别:C={c1,c2,...,cK}C = \{c_1,c_2,...,c_K\}C={c1​,c2​,...,cK​}

实例中:C={正常邮件,垃圾邮件}C=\{正常邮件,垃圾邮件 \}C={正常邮件,垃圾邮件}

样本空间可以描述为:

T={(x(1),y(1)),(x(2),y(2)),...,(x(N),y(N))}(1)T = \{(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),...,(x^{(N)},y^{(N)})\} \tag{1}T={(x(1),y(1)),(x(2),y(2)),...,(x(N),y(N))}(1)

目标是求所有文档的最大似然概率:

p(T)=∏n=1Np(x(n),y(n))=∏n=1Np(x(n)∣y(n))p(y(n))=∏n=1Np(x1(n),x2(n),...,xMn(n)∣y(n))p(y(n))(2)p(T) = \prod_{n=1}^N p(x^{(n)}, y^{(n)}) = \prod_{n=1}^N p(x^{(n)}| y^{(n)}) p(y^{(n)}) = \prod_{n=1}^N p(x_1^{(n)}, x_2^{(n)},...,x_{M_n}^{(n)}| y^{(n)}) p(y^{(n)}) \tag{2}p(T)=n=1∏N​p(x(n),y(n))=n=1∏N​p(x(n)∣y(n))p(y(n))=n=1∏N​p(x1(n)​,x2(n)​,...,xMn​(n)​∣y(n))p(y(n))(2)

1.2 求解目标函数的参数

由朴素贝叶斯的条件独立假设得到:

p(T)=∏n=1N(x1(n)∣y(n))p(x2(n)∣y(n)),...,p(xMn(n)∣y(n))p(y(n))=∏n=1N∏m=1Mnp(xm(n)∣y(n))p(y(n))(3)p(T) = \prod_{n=1}^N (x_1^{(n)} |y^{(n)}) p( x_2^{(n)}|y^{(n)}),...,p(x_{M_n}^{(n)}| y^{(n)}) p(y^{(n)}) = \prod_{n=1}^N \prod_{m=1}^{Mn} p(x_m^{(n)}| y^{(n)}) p(y^{(n)}) \tag{3}p(T)=n=1∏N​(x1(n)​∣y(n))p(x2(n)​∣y(n)),...,p(xMn​(n)​∣y(n))p(y(n))=n=1∏N​m=1∏Mn​p(xm(n)​∣y(n))p(y(n))(3)

其中p(xm(n)∣y(n))p(x_m^{(n)}| y^{(n)})p(xm(n)​∣y(n))表示的含义是对于第nnn个样本而言,在已知输出标签的情况下,输入数据的第mmm个元素出现的概率。为了后面继续化简,可以做以下假设:
设:输入数据XXX中所有元素的集合为V=v1,v2,...,vWV={v_1,v_2,...,v_W}V=v1​,v2​,...,vW​,即共有WWW个不同的元素;αw(n)\alpha_w^{(n)}αw(n)​表示VVV中第www个元素在第nnn个样本中出现的次数。
则(3)式就可以表示为:

p(T)=∏n=1N∏w=1Wp(vw(n)∣y(n))αw(n)p(y(n))(4)p(T) = \prod_{n=1}^N \prod_{w=1}^{W} p(v_w^{(n)}| y^{(n)})^{\alpha_w^{(n)}} p(y^{(n)}) \tag{4}p(T)=n=1∏N​w=1∏W​p(vw(n)​∣y(n))αw(n)​p(y(n))(4)

又有输出类别集合C={c1,c2,...,cK}C = \{c_1,c_2,...,c_K\}C={c1​,c2​,...,cK​},设βk(n)\beta_k^{(n)}βk(n)​表示第nnn个样本是否属于第ckc_kck​类,如果是则为1,否则为0.
所以(4)式又可以表示为:

p(T)=∏n=1N∏w=1W∏c=1Kp(vw(n)∣y(n)=ck)αw(n)∗βk(n)p(y(n)=ck)βk(n)(5)p(T) = \prod_{n=1}^N \prod_{w=1}^{W} \prod_{c=1}^K p(v_w^{(n)}| y^{(n)}=c_k)^{\alpha_w^{(n)} * \beta_k^{(n)}} p(y^{(n)} = c_k)^{\beta_k^{(n)}} \tag{5}p(T)=n=1∏N​w=1∏W​c=1∏K​p(vw(n)​∣y(n)=ck​)αw(n)​∗βk(n)​p(y(n)=ck​)βk(n)​(5)

对上式求对数:

log⁡p(T)=∑n=1N∑w=1W∑c=1K[(αw(n)∗βk(n))log⁡p(vw(n)∣y(n)=ck)+βk(n)log⁡p(y(n)=ck)](6)\log p(T) = \sum_{n=1}^N \sum_{w=1}^{W} \sum_{c=1}^K [(\alpha_w^{(n)} * \beta_k^{(n)}) \log p(v_w^{(n)}| y^{(n)}=c_k) + \beta_k^{(n)} \log p(y^{(n)} = c_k)] \tag{6}logp(T)=n=1∑N​w=1∑W​c=1∑K​[(αw(n)​∗βk(n)​)logp(vw(n)​∣y(n)=ck​)+βk(n)​logp(y(n)=ck​)](6)

到这一步就得到了我们想要求解的目标函数,目标就是:

max⁡log⁡p(T)\max \log p(T)maxlogp(T)

需要求解的参数分别就是∑n=1Np(vw(n)∣y(n)=ck)\sum_{n=1}^N p(v_w^{(n)}| y^{(n)}=c_k)∑n=1N​p(vw(n)​∣y(n)=ck​)和∑n=1Np(y(n)=ck)\sum_{n=1}^N p(y^{(n)} = c_k)∑n=1N​p(y(n)=ck​), 为了方便表示,设:

γwk=∑n=1Np(vw(n)∣y(n)=ck)(7)\gamma_{wk} = \sum_{n=1}^N p(v_w^{(n)}| y^{(n)}=c_k) \tag{7}γwk​=n=1∑N​p(vw(n)​∣y(n)=ck​)(7)

ξk=∑n=1Np(y(n)=ck)(8)\xi_k = \sum_{n=1}^N p(y^{(n)} = c_k) \tag{8}ξk​=n=1∑N​p(y(n)=ck​)(8)

则求:

max⁡γwk,ξk∑n=1N∑w=1W∑c=1K[(αw(n)∗βk(n))log⁡γwk(n)+βk(n)log⁡ξk(n)](9)\max_{\gamma_{wk},\xi_k} \sum_{n=1}^N \sum_{w=1}^{W} \sum_{c=1}^K [(\alpha_w^{(n)} * \beta_k^{(n)}) \log \gamma_{wk}^{(n)}+ \beta_k^{(n)} \log \xi_k^{(n)}] \tag{9}γwk​,ξk​max​n=1∑N​w=1∑W​c=1∑K​[(αw(n)​∗βk(n)​)logγwk(n)​+βk(n)​logξk(n)​](9)

1.求解ξk\xi_kξk​:
有(9)式可以得到:

∑n=1N∑c=1Kβk(n)log⁡ξk(n) \sum_{n=1}^N \sum_{c=1}^K \beta_k^{(n)} \log \xi_k^{(n)}n=1∑N​c=1∑K​βk(n)​logξk(n)​

注意到约束条件∑c=1Kξk=1\sum_{c=1}^K \xi_k = 1∑c=1K​ξk​=1,利用拉格朗日乘子法,写出拉格朗日函数:

∑n=1N∑c=1Kβk(n)log⁡ξk(n)+λ(∑c=1Kξk−1) \sum_{n=1}^N \sum_{c=1}^K \beta_k^{(n)} \log \xi_k^{(n)} + \lambda(\sum_{c=1}^K \xi_k - 1)n=1∑N​c=1∑K​βk(n)​logξk(n)​+λ(c=1∑K​ξk​−1)

求其偏导数等于0得:

∂∂ξk[∑n=1N∑c=1Kβk(n)log⁡ξk(n)+λ(∑c=1Kξk−1)]=0\frac {\partial}{\partial \xi_k}[ \sum_{n=1}^N \sum_{c=1}^K \beta_k^{(n)} \log \xi_k^{(n)} + \lambda(\sum_{c=1}^K \xi_k - 1) ]= 0∂ξk​∂​[n=1∑N​c=1∑K​βk(n)​logξk(n)​+λ(c=1∑K​ξk​−1)]=0

得到:

∑n=1Nβk(n)∑n=1Nξk(n)+λ=0\frac {\sum_{n=1}^N \beta_k^{(n)}} {\sum_{n=1}^N \xi_k^{(n)}} + \lambda = 0∑n=1N​ξk(n)​∑n=1N​βk(n)​​+λ=0

则:

ξk=∑n=1Nβk(n)−λ\xi_k = \frac {\sum_{n=1}^N \beta_k^{(n)}} {- \lambda} ξk​=−λ∑n=1N​βk(n)​​

将上式带入∑c=1Kξk=1\sum_{c=1}^K \xi_k = 1∑c=1K​ξk​=1:

−λ=∑c=1K∑n=1Nβk(n)=N- \lambda = \sum_{c=1}^K \sum_{n=1}^N \beta_k^{(n)} = N−λ=c=1∑K​n=1∑N​βk(n)​=N

最后得到:

ξk=∑n=1Nβk(n)N(10)\xi_k = \frac {\sum_{n=1}^N \beta_k^{(n)}} {N} \tag{10}ξk​=N∑n=1N​βk(n)​​(10)

上式的物理意义:
左边:ξk\xi_kξk​表示kkk类的概率,这个属于先验概率
右边:所有标签中属于kkk类的数目除以总的样本数目。
实例中ξk=垃圾邮件=1/2\xi_{k=垃圾邮件} = 1/2ξk=垃圾邮件​=1/2

2.求解γwk\gamma_{wk}γwk​:
由(9)式可以得到:

∑n=1N∑w=1W∑c=1Kαw(n)∗βk(n)log⁡γwk(n) \sum_{n=1}^N \sum_{w=1}^{W} \sum_{c=1}^K \alpha_w^{(n)} * \beta_k^{(n)} \log \gamma_{wk}^{(n)}n=1∑N​w=1∑W​c=1∑K​αw(n)​∗βk(n)​logγwk(n)​

注意到约束条件∑w=1Wγwk=1\sum_{w=1}^W \gamma_{wk} = 1∑w=1W​γwk​=1,利用拉格朗日乘子法,写出拉格朗日函数:

∑n=1N∑w=1W∑c=1Kαw(n)∗βk(n)log⁡γwk(n)+λ(∑w=1Wγwk−1) \sum_{n=1}^N \sum_{w=1}^{W} \sum_{c=1}^K \alpha_w^{(n)} * \beta_k^{(n)} \log \gamma_{wk}^{(n)} + \lambda (\sum_{w=1}^W \gamma_{wk} - 1) n=1∑N​w=1∑W​c=1∑K​αw(n)​∗βk(n)​logγwk(n)​+λ(w=1∑W​γwk​−1)

求其偏导等于0得:

∂∂γwk[∑n=1N∑w=1W∑c=1Kαw(n)∗βk(n)log⁡γwk(n)+λ(∑w=1Wγwk−1)]=0\frac {\partial} {\partial \gamma_{wk}} [ \sum_{n=1}^N \sum_{w=1}^{W} \sum_{c=1}^K \alpha_w^{(n)} * \beta_k^{(n)} \log \gamma_{wk}^{(n)} + \lambda (\sum_{w=1}^W \gamma_{wk} - 1)] = 0∂γwk​∂​[n=1∑N​w=1∑W​c=1∑K​αw(n)​∗βk(n)​logγwk(n)​+λ(w=1∑W​γwk​−1)]=0

得到:

∑n=1Nαw(n)∗βk(n)∑n=1Nγwk(n)+λ=0\frac { \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)} }{ \sum_{n=1}^N \gamma_{wk}^{(n)}} + \lambda = 0∑n=1N​γwk(n)​∑n=1N​αw(n)​∗βk(n)​​+λ=0

则:

γwk=∑n=1Nαw(n)∗βk(n)−λ\gamma_{wk} = \frac { \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)} }{- \lambda} γwk​=−λ∑n=1N​αw(n)​∗βk(n)​​

将上式带入∑w=1Wγwk=1\sum_{w=1}^W \gamma_{wk} = 1∑w=1W​γwk​=1得到:

−λ=∑w=1W∑n=1Nαw(n)∗βk(n)- \lambda = \sum_{w=1}^W \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)}−λ=w=1∑W​n=1∑N​αw(n)​∗βk(n)​

最后求得:

γwk=∑n=1Nαw(n)∗βk(n)∑w=1W∑n=1Nαw(n)∗βk(n)(11)\gamma_{wk} = \frac { \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)} }{\sum_{w=1}^W \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)}} \tag{11}γwk​=∑w=1W​∑n=1N​αw(n)​∗βk(n)​∑n=1N​αw(n)​∗βk(n)​​(11)

上式表示的运算是:第kkk类中第www个单词的个数除以第kkk个类中的所有单词个数

1.3 拉普拉斯平滑处理

用极大似然估计会出现概率为0的情况,可以使用拉普拉斯平滑处理。

(10)式可以表示为:

ξk=∑n=1Nβk(n)+λN+Kλ(12)\xi_k = \frac {\sum_{n=1}^N \beta_k^{(n)} + \lambda} {N + K\lambda} \tag{12}ξk​=N+Kλ∑n=1N​βk(n)​+λ​(12)

(11)式可以表示为:

γwk=∑n=1Nαw(n)∗βk(n)+λ∑w=1W∑n=1Nαw(n)∗βk(n)+Wλ(13)\gamma_{wk} = \frac { \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)} + \lambda} {\sum_{w=1}^W \sum_{n=1}^N \alpha_w^{(n)} * \beta_k^{(n)} + W \lambda} \tag{13}γwk​=∑w=1W​∑n=1N​αw(n)​∗βk(n)​+Wλ∑n=1N​αw(n)​∗βk(n)​+λ​(13)

得到(12)(13)式仍然分别满足∑c=1Kξk=1\sum_{c=1}^K \xi_k = 1∑c=1K​ξk​=1和∑w=1Wγwk=1\sum_{w=1}^W \gamma_{wk} = 1∑w=1W​γwk​=1。

2. 朴素贝叶斯python实现
2.1 模型实现
import numpy as np

class MyNaiveBayes(object):
def __init__(self, laplace=1):
"""
朴素贝叶斯
:param laplace: 拉普拉斯平滑项,默认值为1
:param N: 输入样本的个数
:param W: 输入样本的元素集合数目
:param K: 输入标签类的数目
:param V: 输入样本的元素集合
:param C: 输入标签的类的集合

模型参数
:param xi: 参数,先验概率,表示每一类别概率,维度(K,)
:param gamma: 参数,条件概率,表示单词在一个类别中的概率,维度(K, W)
"""
self.laplace = laplace

self.params = {
'xi': None,
'gamma': None
}

self.N = None
self.V = None
self.C = None

self.W = None
self.K = None

self.is_adding_lambda = True  # 是否应用拉普拉斯平滑

def _init_params(self):
"""
初始化模型参数
:return: None
"""
xi = np.zeros(self.K)
gamma = np.zeros((self.K, self.W))
self.params['xi'] = xi
self.params['gamma'] = gamma

def fit(self, X, y, V, C):
"""
输入样本,训练模型
:param X: 训练输入输入(N, M_N)
:param y: 训练输入标签(N)
:param V: 输入样本的元素集合
:param C: 输入标签的类的集合
:return: None
"""
X = np.array(X)
y = np.array(y)

self.N = len(X)
self.V = V
self.C = C

self.W = len(V)
self.K = len(C)

self._init_params()

for c in C:
if self.is_adding_lambda:
self.params['xi'][c] = ((y == c).sum() + self.laplace) / (self.N + self.K * self.laplace)
else:
self.params['xi'][c] = (y == c).sum() / self.N

split_x = [[] for _ in range(self.K)]
for x_s, y_s in zip(X, y):
for c in C:
if y_s == c:
split_x[c].extend(x_s)
split_x = np.array([np.array(x) for x in split_x])

for c in C:
for v in V:
if self.is_adding_lambda:
self.params['gamma'][c][v] = ((np.array(split_x[c]) == v).sum() + self.laplace) / (split_x[c].sum() + self.W * self.laplace)
else:
self.params['gamma'][c][v] = (np.array(split_x[c]) == v).sum()  / split_x[c].sum()

def predict(self, X):
"""
求取对数似然最大的一个标签
:param X: 输出数据
:return: 最大概率的标签
"""
result_list = np.zeros(self.K)

for c in self.C:
result_list[c] = np.log(self.params['xi'][c])  # 先加入先验概率的对数
for x_s in X:  # 后加入每个单词的条件概率
result_list[c] += np.log(self.params['gamma'][c][x_s])
return np.argmax(result_list)
2.1 模型测试
def generate_data():
O = [['明天', '早上', '参加', '早会'],
['希望', '明天', '听到', '好消息'],
['欢迎', '明天', '订阅', '购买'],
['听到', '我们的', '产品']]
word2index = {}
index2word = {}
for sentence in O:
for word in sentence:
if word not in word2index.keys():
word2index[word] = len(word2index)
index2word[len(index2word)] = word
print(word2index)
print(index2word)
O_input = []
for sentence in O:
O_input.append([word2index[word] for word in sentence])
print(O_input)
C = ['正常邮件', '垃圾邮件']
C_input = [0, 1]
V = [i for i in range(len(word2index))]
y = [0, 0, 1, 1]
return O_input, y, V, C_input

def run_my_model():
X, y, V, C = generate_data()
my = MyNaiveBayes()
my.fit(X, y, V, C)

X_test = [4, 1, 2]
y_test = my.predict(X_test)
print(y_test)

输出结果为:
0

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐