数据挖掘十大算法之 naïve Bayes

2021-01-25 18:05:11 浏览数 (1)

公号:Python 自习室

朴素贝叶斯法是基于贝叶斯定理和特征条件独立假设的分类方法。朴素贝叶斯法实现简单,学习与预测的效率都很高,被广泛应用于文本分类、垃圾邮件过滤、自然语言处理等场景。下面我们来介绍贝叶斯定理,在介绍贝叶斯定理之前,先介绍下条件概率和全概率公式。

条件概率

所谓条件概率,就是在事件 B 发生的条件下,事件 A 发生的概率,用 P(A|B) 来表示。在下面的文氏图中,定义了事件 AB,以及他们的交集 Acap Boverline AA 的补集。则在事件 B 发生的条件下,事件 A 发生的概率为 P(A|B) = displaystyle{P (A cap B)} over displaystyle{P(B)} => P(A cap B)=P(A|B)P(B);同理可得,P(B|A) = displaystyle{P (A cap B)} over displaystyle{P(A)} => P(A cap B)=P(B|A)P(A),于是 P(A|B)P(B) = P(B|A)P(A)

全概率公式

在上面的文氏图中,P(B) = P(A cap B) P(overline A cap B),代入上面的条件概率公式,P(B) = P(A)P(B|A) P(overline A)P(B|overline A),这便是全概率公式。

贝叶斯定理

贝叶斯定理是 Thomas Bayes 为了解决一个逆概率问题所写的一篇文章。在当时,人们已经能够计算正向概率。例如,一个袋子里装有 m 个白球 和 n 个黑球,把手伸进去摸到白球的概率是多少?这就是一个正向概率问题,而逆概率问题正好反过来,我们事先并不知道袋子里黑球和白球的比例,而是不断伸手去摸球,根据摸到球的颜色来推测黑球与白球的比例。由上面的条件概率,我们可以推导出 P(A|B) = displaystyle P(B|A)P(A) over displaystyle P(B) 这便是贝叶斯定理。P(A) 称为先验概率,P(A|B) 称为后验概率,即在事件 B 发生之后,我们对事件 A 概率的重新评估。

朴素贝叶斯分类器

朴素贝叶斯的思想基础是,对于待分类项 x,求解在 x 出现的条件下各个类别出现的概率,哪个最大,就认为 x 属于哪个类别。设输入空间 mathcal X subseteq R^nn 维向量的集合,输出空间为类标记集合 mathcal Y = {c_1, c_2, ..., c_k},输入为特征向量 x in mathcal X,输出为类标记 y in mathcal YX 是定义在输入空间 mathcal X 上的随机向量,Y 是定义在输出空间 mathcal Y 上的随机变量。假设有一个待分类项 x,为了确定 x 属于哪个类别,我们需要计算 P(Y=c_k|X=x), k=1, 2, ..., K,选取概率P(Y=c_k|X=x) 最大时对应的类别为 x 对应的类别。基于贝叶斯定理可以写为: P(Y=c_k|X=x) = displaystyle P(X=x|Y=c_k)P(Y=c_k) over displaystyle P(X=x) ,k=1, 2, ..., K 基于此公式来估计后验概率 P(Y=c_k|X=x) 的主要困难在于:条件概率 P(X=x|Y=c_k) 是所有特征上的联合概率,难以从有限的训练样本直接估计而得。为避开这个障碍,朴素贝叶斯分类器采用了“特征条件独立假设”:对已知类别,假设所有特征相互独立。换言之,假设每个特征独立地对分类结果发生影响(这也是算法被叫做朴素贝叶斯分类器的原因)。基于特征条件独立假设,可将上述公式重写为: displaystyle P(Y=c_k|X=x)

= displaystyle prod_{j=1}^nP(X^{(j)}=x^{(j)}|Y=c_k)P(Y=c_k) over displaystyle P(X=x)k=1,2,...,K 由于对所有的类别,P(X=x) 相同,所以 y = {underset {c_k}{operatorname {arg,max} }} P(Y=c_k)displaystyleprod_{j=1}^nP(X^{(j)}=x^{(j)}|Y=c_k)y 便是 x 的分类) 下面便是如何求得,P(Y=c_k)P(X^{(j)}=x^{(j)}|Y=c_k)

极大似然估计

在朴素贝叶斯分类器中,学习意味着估计 P(Y=c_k)P(X^{(j)}=x^{(j)}|Y=c_k)。可以应用极大似然估计法估计相应的概率。我们先通过一个例子来了解下极大似然估计。假设一个袋子里装有黑白两种颜色的球,黑白球的数量以及比例未知,我们不可以一次把袋子中的球倒出来,只能每次从袋子中任意取一个球,记录球的颜色,然后将球放回袋子。假如我们重复取球 100 次之后,在取出的 100 个球中,有白球 60 个,黑球 40 个,那么请问袋子里黑白球的比例最有可能是多少?也许你会回答黑白球的比例为 4:6,那么这个答案背后的理论支撑是什么呢?我们假设袋子里黑球的比例为 p,那么白球的比例为 1-p,因为每抽一个球出来,在记录颜色之后,把抽出的球放回了袋子里,所以每次抽出来的球的颜色服从同一独立分布。这里我们把一次抽出来球的颜色称为一次抽样。题目中在一百次抽样中,60 次是白球的,40 次为黑球事件的概率是P(样本结果|M)。如果第一次抽样的结果记为 x_1,第二次抽样的结果记为 x_2...,第一百次抽样的结果为 x_{100}。那么样本结果为 (x_1,x_2.....,x_{100})。这样,我们可以得到如下表达式:

P(样本结果|M)

= P(x_1,x_2,…,x_{100}|M)

= P(x_1|M)P(x_2|M)…P(x_{100}|M)=<br> p^{40}(1-p)^{60}

由于最后的概率只和 p 有关,不同的 p 会导致不同的结果。那么如何求 p 的值呢?极大似然估计采取的方法是让这个样本结果出现的可能性最大,也就是使得p^{40}(1-p)^{60}值最大,那么我们就可以看成是p的方程,求导即可!令导数为0,即可求出 p=0.4。这便是极大似然估计的思想。

先验概率 P(Y=c_k) 的极大似然估计是 P(Y=c_k) = displaystylesum_{i=1}^NI(y_i=c_k) over displaystyle Nk=1,2,...,K, 设第 j 个特征 x^{(j)} 可能取值的集合为 {a_{j1}, a_{j2},...,a_{js_j}},条件概率 P(X^{(j)}=a_{jl}|Y=c_k) 的极大似然估计是

P(X^{(j)}=a_{jl}|Y=c_k) = displaystylesum_{i=1}^NI(x_i^{(j)} = a_{jl}, y_i=c_k) over displaystylesum_{i=1}^N(y_i=c_k)j=1,2,...,n;l=1,2,...,S_j;k=1,2,...,K, 式中,x_i^{(j)} 是第 i 个样本的第 j 个特征;a_{jl} 是第 j 个特征可能取的第 l 个值;I 为指示函数。

例子

下面我们通过一个例子来看下朴素贝叶斯分类器的工作过程,下表格包含了天气状况和是否去打高尔夫的关系,表中 outlook、temperature、humidity、windy 为特征,取值的集合分别为 {rainy, overcast, sunny},{hot, mild, cool},{high, normal},{false, true},playgolf 为类标记,取值为 {no, yes}。如果今天天气的状况为 (sunny, hot, normal, false),我们是否要去打高尔夫球呢?

outlook

temperature

humidity

windy

playgolf

rainy

hot

high

false

no

rainy

hot

high

true

no

overcast

hot

high

false

yes

Sunny

mild

high

false

yes

Sunny

cool

normal

false

yes

Sunny

cool

normal

true

no

overcast

cool

normal

true

yes

rainy

mild

high

false

no

rainy

cool

normal

false

yes

Sunny

mild

normal

false

yes

rainy

mild

normal

true

yes

overcast

mild

high

true

yes

overcast

hot

normal

false

yes

Sunny

mild

high

true

no

根据极大似然估计,容易计算下列概率:

P(playgolf=yes) = 9 over 14,P(playgolf=no) = 5 over 14 P(outlook=rainy|playgolf=yes) = 2 over 9,P(outlook=overcast|playgolf=yes) = 4 over 9,P(outlook=sunny|playgolf=yes) = 1 over 3, P(outlook=rainy|playgolf=no) = 3 over 5,P(outlook=overcast|playgolf=no) = 0 over 5,P(outlook=sunny|playgolf=no) = 2 over 5

P(temperature=hot|playgolf=yes) = 2 over 9,P(temperature=mild|playgolf=yes) = 4 over 9,P(temperature=cool|playgolf=yes) = 1 over 3, P(temperature=hot|playgolf=no) = 2 over 5,P(temperature=mild|playgolf=no) = 2 over 5,P(temperature=cool|playgolf=no) = 1 over 5

P(humidity=high|playgolf=yes) = 1 over 3,P(humidity=normal|playgolf=yes) = 2 over 3, P(humidity=high|playgolf=no) = 4 over 5,P(humidity=normal|playgolf=no) = 1 over 5

P(windy=false|playgolf=yes) = 2 over 3,P(windy=true|playgolf=yes) = 1 over 3, P(windy=false|playgolf=no) = 2 over 5,P(windy=true|playgolf=no) = 3 over 5

对给定的(sunny, hot, normal, false)计算:

P(playgolf=yes)P(outlook=sunny|playgolf=yes)P(temperature=hot|playgolf=yes)

P(humidity=Normal|playgolf=yes)P(windy=false|playgolf=yes)

= 9 over 14 1 over 3 2 over 9 2 over 3 2 over 3 approx 0.0211

P(playgolf=no)P(outlook=sunny|playgolf=no)P(temperature=hot|playgolf=no)

P(humidity=normal|playgolf=no)P(windy=false|playgolf=no)

= 5 over 14 2 over 5 2 over 5 1 over 5 2 over 5 approx 0.0046

由于 0.0211 > 0.0046,所以今天去打高尔夫。

贝叶斯估计

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

P_lambda(X^{(j)}=a_{jl}|Y=c_k) = displaystylesum_{i=1}^NI(x_i^{(j)} = a_{jl}, y_i=c_k) lambda over displaystylesum_{i=1}^N(y_i=c_k) S_jlambda,式中lambda geq 0。 等价于在随机变量各个取值的频数上赋予一个正数 lambda > 0。当 lambda = 0 时就是极大似然估计。常取 lambda = 1,这时称为拉普拉斯平滑。同样,先验概率的贝叶斯估计是 P_lambda(Y=c_k) = displaystylesum_{i=1}^NI(y_i=c_k) lambda over displaystyle N Klambda, 使用贝叶斯估计计算上面例子中的概率为:

P(playgolf=yes) = 10 over 16,P(playgolf=no) = 6 over 16 P(outlook=rainy|playgolf=yes) = 1 over 4,P(outlook=Overcast|playgolf=yes) = 5 over 12, P(outlook=sunny|playgolf=yes) = 1 over 3,P(outlook=rainy|playgolf=no) = 1 over 2,P(outlook=Overcast|playgolf=no) = 1 over 8,P(outlook=sunny|playgolf=no) = 3 over 8

P(temperature=hot|playgolf=yes) = 1 over 4,P(temperature=mild|playgolf=yes) = 5 over 12, P(temperature=cool|playgolf=yes) = 1 over 3,P(temperature=hot|playgolf=no) = 3 over 8,P(temperature=mild|playgolf=no) = 3 over 8,P(temperature=cool|playgolf=no) = 1 over 4

P(humidity=high|playgolf=yes) = 4 over 11,P(humidity=normal|playgolf=yes) = 7 over 11, P(humidity=high|playgolf=no) = 5 over 7,P(humidity=normal|playgolf=no) = 2 over 7

P(windy=false|playgolf=yes) = 7 over 11,P(windy=true|playgolf=yes) = 4 over 11, P(windy=false|playgolf=no) = 3 over 7,P(windy=true|playgolf=no) = 4 over 7

对给定的(sunny, hot, normal, false)计算:

P(playgolf=Yes)P(outlook=sunny|playgolf=yes)P(temperature=hot|playgolf=yes)

P(humidity=normal|playgolf=yes)P(windy=false|playgolf=yes)

= 10 over 16 1 over 3 1 over 4 7 over 11 7 over 11 approx 0.0211

P(playgolf=no)P(outlook=sunny|playgolf=no)P(temperature=hot|playgolf=no)

P(humidity=normal|playgolf=no)P(windy=false|playgolf=no)

= 6 over 14 2 over 5 2 over 5 1 over 5 2 over 5 approx 0.0065

由于 0.0211 > 0.0065,所以今天去打高尔夫。

鸢尾花分类

  • 导入库
代码语言:txt复制
import pandas as pd
from sklearn import metrics
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
from sklearn.naive_bayes import GaussianNB
  • 读取数据
代码语言:txt复制
iris_data = pd.read_csv('Iris.csv')
  • 将数据集分成训练数据集和测试数据集
代码语言:txt复制
y = iris_data['Species']
x = iris_data[['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm']]
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.3, random_state=33)
  • 使用训练数据对模型进行训练,并使用得到的模型对测试数据进行测试。
代码语言:txt复制
gnb = GaussianNB()
gnb.fit(train_x, train_y)
predict_y = gnb.predict(test_x)
  • 输出测试结果
代码语言:txt复制
print("NB准确率: %.4lf" % accuracy_score(test_y, predict_y))
  • output
代码语言:txt复制
NB准确率: 0.9556

糖尿病的预测

糖尿病的预测是根据患者的一些信息来预测患者是否有糖尿病。下面我们通过 Scikit-learn 中的 $k$-NN 算法对患者是否患有糖尿病进行预测。

  • 导入库
代码语言:txt复制
import pandas as pd
from sklearn import metrics
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
  • 读取数据
代码语言:txt复制
diabetes_data = pd.read_csv('diabetes.csv')
  • 对数据进行清洗,对于某列数据中的0值,使用这一列值的平均值进行填充。
代码语言:txt复制
diabetes_data.replace({
    'Glucose': 0,
    'BloodPressure': 0,
    'SkinThickness': 0,
    'BMI': 0,
    'Insulin': 0
}, np.NaN, inplace=True)

glucose_mean = diabetes_data['Glucose'].mean()
blood_pressure_mean = diabetes_data['BloodPressure'].mean()
skin_thickness_mean = diabetes_data['SkinThickness'].mean()
bmi_mean = diabetes_data['BMI'].mean()
insulin_mean = diabetes_data['Insulin'].mean()

diabetes_data['Glucose'].replace(np.NaN, glucose_mean, inplace=True)
diabetes_data['BloodPressure'].replace(np.NaN, blood_pressure_mean, inplace=True)
diabetes_data['SkinThickness'].replace(np.NaN, skin_thickness_mean, inplace=True)
diabetes_data['BMI'].replace(np.NaN, bmi_mean, inplace=True)
diabetes_data['Insulin'].replace(np.NaN, insulin_mean, inplace=True)
  • 将数据集分成训练数据集和测试数据集。
代码语言:txt复制
y = diabetes_data['Outcome']
x = diabetes_data[['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age']]
train_x, test_x, train_y, test_y = train_test_split(x, y, test_size=0.2, random_state=0)
  • 对数据进行规范化。
代码语言:txt复制
sc_x = StandardScaler()
train_x = sc_x.fit_transform(train_x)
test_x = sc_x.fit_transform(test_x)
  • 使用训练数据对模型进行训练,并使用得到的模型对测试数据进行测试。
代码语言:txt复制
gnb = GaussianNB()
gnb.fit(train_x, train_y)
predict_y = gnb.predict(test_x)
  • 输出测试结果
代码语言:txt复制
print("NB 准确率: %.4lf" % accuracy_score(test_y, predict_y))
  • output
代码语言:txt复制
NB 准确率: 0.7835

总结

本文阐述了朴素贝叶斯法的理论知识,并通过两个例子介绍了朴素贝叶斯法的实际应用。

0 人点赞