《统计学习方法》—— 朴素贝叶斯方法、详细推导及其python3实现(二)

前言

在上一篇博客中,我们介绍了朴素贝叶斯方法以及详细推导。在这篇博客中,我们将介绍朴素贝叶斯的python3实现代码。

这里,我们将算法复述如下:

  • 输入:数据集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T=\{(x_1, y_1), (x_2, y_2), ..., (x_N, y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)},其中, x i = ( x i ( 1 ) , x i ( 2 ) , . . . , x i ( n ) ) x_i=(x_i^{(1)}, x_i^{(2)}, ..., x_i^{(n)}) xi=(xi(1),xi(2),...,xi(n)) x i ( j ) x_i^{(j)} xi(j) x i x_i xi的第 j j j个特征, x i ( j ) ∈ { a j 1 , a j 2 , . . . , a j S j } x_i^{(j)}\in\{a_{j1}, a_{j2}, ..., a_{jS_j}\} xi(j){aj1,aj2,...,ajSj} y i ∈ { c 1 , c 2 , . . . , c K } y_i\in\{c_1, c_2, ..., c_K\} yi{c1,c2,...,cK};实例 x x x
  • 输出:实例 x x x 的分类 y y y

(1) 先验概率及条件概率
P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) N P(Y=c_k)=\frac{\sum_{i=1}^NI(y_i=c_k)}{N} P(Y=ck)=Ni=1NI(yi=ck)
P ( X ( j ) = a j l ∣ Y = c k ) = ∑ i = 1 N I ( x i ( j ) = a j l , y i = c k ) ∑ i = 1 N I ( y i = c k ) P(X^{(j)}=a_{jl}|Y=c_k)=\frac{\sum_{i=1}^NI(x_i^{(j)}=a_{jl}, y_i=c_k)}{\sum_{i=1}^NI(y_i=c_k)} P(X(j)=ajlY=ck)=i=1NI(yi=ck)i=1NI(xi(j)=ajl,yi=ck)

(2) 对于给定的 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) x=(x^{(1)}, x^{(2)}, ..., x^{(n)}) x=(x(1),x(2),...,x(n)),计算
P ( Y = c k ) Π j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) P(Y=c_k)\Pi_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k) P(Y=ck)Πj=1nP(X(j)=x(j)Y=ck)

(3) 确定实例 x x x 的类
y = arg max ⁡ c k P ( Y = c k ) Π j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) y=\argmax_{c_k}P(Y=c_k)\Pi_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k) y=ckargmaxP(Y=ck)Πj=1nP(X(j)=x(j)Y=ck)

3. 贝叶斯估计

从上述算法的步骤(1)和步骤(2),可以看到,计算概率的分子分母可能为0。比如,计算先验概率的时候,假设类别有100种,但是我们只有50个数据,此时,必然出现某些类别出现的概率为0;再比如,计算条件概率时,相亲对象数据特征有 高矮 和 胖瘦 这两个维度,如果我们只取了高个子数据,就会导致 P ( x i ( 1 ) = 矮 子 , y i = c k ) P(x_i^{(1)}=矮子, y_i=c_k) P(xi(1)=,yi=ck) 恒为0。

为了避免上述的计算概率为0的情况,我们在分子分母上分别加上一个正数 λ \lambda λ
P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) + λ N + K ⋅ λ P(Y=c_k)=\frac{\sum_{i=1}^NI(y_i=c_k)+\lambda}{N+K\cdot \lambda} P(Y=ck)=N+Kλi=1NI(yi=ck)+λ

P ( X ( j ) = a j l ∣ Y = c k ) = ∑ i = 1 N I ( x i ( j ) = a j l , y i = c k ) + λ ∑ i = 1 N I ( y i = c k ) + S j ⋅ λ P(X^{(j)}=a_{jl}|Y=c_k)=\frac{\sum_{i=1}^NI(x_i^{(j)}=a_{jl}, y_i=c_k)+\lambda}{\sum_{i=1}^NI(y_i=c_k)+S_j\cdot \lambda} P(X(j)=ajlY=ck)=i=1NI(yi=ck)+Sjλi=1NI(xi(j)=ajl,yi=ck)+λ

可以简单验证,上面的表达式依然是概率。

4. 代码实现

注意:此处可以参考@miangangzhen的代码。这里,我们将用非常简单的代码来实现该问题的预测功能。

import pandas as pd
import numpy as np


# 载入数据
def load_data(file):
    data = pd.read_csv(file, header=None, names=['data1', 'data2', 'label'], sep=' ')
    return data


x_y_data = load_data('D:/pycharm/myproject/data.txt')


# 数据数量
N, _ = x_y_data.shape
##############################
# 类别及其数量
categories = x_y_data['label'].value_counts()
print('类别及其数量为\n', categories)
# 先验概率
pre_possibility = categories / N
print('先验概率为\n', pre_possibility)
##############################
# 同时限定某维度的值和类别时,数据的数量counts以及条件概率
# 维度1
dim1_cate = x_y_data.groupby(['data1', 'label']).count()
dim1_cate = dim1_cate.reset_index().rename(columns={'data2': 'counts'})
dim1_cate['possibilities'] = dim1_cate.apply(lambda x: x.counts / categories[x.label], axis=1)
print('维度1+类别+条件概率:\n', dim1_cate)
# 维度2
dim2_cate = x_y_data.groupby(['data2', 'label']).count()
dim2_cate = dim2_cate.reset_index().rename(columns={'data1': 'counts'})
dim2_cate['possibilities'] = dim2_cate.apply(lambda x: x.counts / categories[x.label], axis=1)
print('维度2+类别+条件概率:\n', dim2_cate)
##############################
# 计算 x=(2, S)的类标记
x = (2, 'S')
res = []
for label in list(categories.index): # 遍历类别
    #print('label=', label)
    # 计算该类别下的后验概率
    post_possibility = pre_possibility[label]
    # 遍历特征
    dim1_con_pos = dim1_cate[(dim1_cate['label'] == label) & (dim1_cate['data1'] == x[0])].iloc[0, 3]
    #print(dim1_con_pos)
    dim2_con_pos = dim2_cate[(dim2_cate['label'] == label) & (dim2_cate['data2'] == x[1])].iloc[0, 3]
    #print(dim2_con_pos)
    post_possibility *= dim1_con_pos * dim2_con_pos
    res.append((label, post_possibility))
    #print('label=', label, ' post=', post_possibility)

print('类标记及其对应后验概率为')
print(res)

结果为

类别及其数量为
  1    9
-1    6
Name: label, dtype: int64
先验概率为
  1    0.6
-1    0.4
Name: label, dtype: float64
维度1+类别+条件概率:
    data1  label  counts  possibilities
0      1     -1       3       0.500000
1      1      1       2       0.222222
2      2     -1       2       0.333333
3      2      1       3       0.333333
4      3     -1       1       0.166667
5      3      1       4       0.444444
维度2+类别+条件概率:
   data2  label  counts  possibilities
0     L     -1       1       0.166667
1     L      1       4       0.444444
2     M     -1       2       0.333333
3     M      1       4       0.444444
4     S     -1       3       0.500000
5     S      1       1       0.111111
类标记及其对应后验概率为
[(1, 0.02222222222222222), (-1, 0.06666666666666667)]

可见,我们应该选取-1作为 x x x的类标记。

在下一篇博客中,我们将介绍决策树算法。

数据:数据来源为《统计学习方法》第二版的例4.1。复制保存为.txt文件。

1 S -1
1 M -1
1 M 1
1 S 1
1 S -1
2 S -1
2 M -1
2 M 1 
2 L 1
2 L 1
3 L 1
3 M 1
3 M 1
3 L 1 
3 L -1

你可能感兴趣的:(机器学习)