【机器学习基础】朴素贝叶斯的算法实现
共 2888字,需浏览 6分钟
·
2021-02-06 16:37
前言
本次我们将梳理下朴素贝叶斯(Naive Bayes)的相关内容。
本文约1.6k字,预计阅读10分钟。
概要
朴素贝叶斯算法是一种适用于二分类和多分类分类问题的「分类算法」。在贝叶斯概率框架下,通过相应推导得知,「期望风险最小化等价于后验概率最大化」。对于后验概率的计算,可以通过「联合概率分布建模」,得到后验概率(「生成模型」);
对于生成模型来说,根据「贝叶斯定理」,可以将其写成:
在朴素贝叶斯中,由于条件概率难以计算,因此提出一个强烈的假设:「特征独立性假设」,即各个特征是独立同分布的,不存在交互,这也是朴素贝叶斯名称的来由。先验概率和条件概率的估计不作展开,感兴趣的可以参考《统计学习方法》,通过转化,最终最大化后验概率(MAP),即「先验概率与类条件概率的乘积」:
【注】期望风险最小化等价于后验概率最大化的推导可以参考《机器学习》,详细的推导,可以参考《统计学习方法》。
算法面试
在算法面试中,设计朴素贝叶斯相关的问题包括:
为什么朴素贝叶斯如此“朴素”? 朴素贝叶斯基本原理和预测过程; 简单说说贝叶斯定理; 使用朴素贝叶斯如何进行垃圾分类?
今天我们讨论的问题是:
❝朴素贝叶斯的算法实现。
❞
对于朴素贝叶斯来说,这既对我们的算法原理进行考察,也检验了编程能力。我以建立整个朴素贝叶斯算法模型类来展开,主要分为:
确定朴素贝叶斯的类型(高斯朴素贝叶斯或者伯努利朴素贝叶斯等); 模型的拟合,重点在于模型到底保存了什么内容; 后验概率的计算; 最大后验概率的输出;
1. 模型类型
对于类条件概率参数的估计,我们采用极大似然估计法,首先最重要的是「假设随便变量(特征)服从什么分布」,对于不同的假设,也对应着不同的朴素贝叶斯,例如伯努利朴素贝叶斯、高斯朴素贝叶斯、多项分布朴素贝叶斯。最常见的是通过假设「高斯分布」,在模型拟合中,「只需要估计训练数据(每个类别的所有样本的每个特征)的平均值和标准偏差」。
因此,我们可以得到初步的框架:
class Gaussian_NaiveBayes:
def init(self):
def mean(self, 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)-1))
2. 模型拟合
通过对朴素贝叶斯原理的理解,我们知道,学习联合概率模型,需要通过极大似然法估计先验概率(假设服从伯努利分布)和类条件概率参数,对于高斯朴素贝叶斯来说,整个训练数据集,我们需要保存:
每个类对应的数量(可以计算先验概率)和总样本数量(可以作为模型的一个属性); 每个类的每个特征的均值与标准偏差(可以计算类条件概率);
综上所述,我们可以通过「字典」的形式进行保存:
因此:
def summarize(self, train_data):
summaries = [(self.mean(column), self.stdev(column), len(column)) for column in zip(*train_data)]
return summaries
def fit(self, X, y):
self.total_rows = len(X)
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()}
3. 后验概率的计算
对于每个类别的后验概率计算,需要求得先验概率和类条件概率。首先对于类条件概率,根据高斯公式求得,
def gaussian_probabality(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
然后迭代计算所有类的后验概率:
def calculate_probabalities(self, input_data):
probalalities = {}
for label, summaries in self.model.items():
probalalities[label] = summaries[0][2] / self.total_rows # 先验
for i in range(len(summaries)):
mean, stdev, _ = summaries[i]
probalalities[label] *= self.gaussian_probabality( # 先验 * 条件概率
input_data[i], mean, stdev)
return probalalities
4. 最大后验概率
最大后验概率的计算就是排序,得到最大概率对应的标签值。对于测试集来说,遍历所有样本进行计算。
def predict(self, X_test):
labels = []
for i in X_test:
label = sorted(
self.calculate_probabalities(i).items(),
key=lambda x: x[-1])[-1][0]
labels.append(label)
return np.array(labels)
总结
以上便是对“朴素贝叶斯算法实现”的总结。最重要的是需要一个完善的类框架,才能够好的结合原理进行代码的复现。至于其他几个问题,比较简单,这里就不作详细讨论。
往期精彩回顾
本站知识星球“黄博的机器学习圈子”(92416895)
本站qq群704220115。
加入微信群请扫码: