1 基本概念
1.1 先验概率(prior probability)
是指根据以往经验和分析得到的概率,如全概率公式,它往往作为"由因求果"问题中的"因"出现的概率。---一般统计得到
1.2 条件概率
条件概率是指事件A在另外一个事件B已经发生条件下的发生概率。条件概率表示为:P(A|B),读作“在B的条件下A的概率”。
条件概率计算公式:P(AB)=P(A)P(B|A)=P(B)P(A|B)
详细:https://www.jianshu.com/p/c59851b1c0f3
1.3 后验概率(观察到事件A发生之后,事件B发生的概率)
后验概率是指,某事件 X=x 已经发生,那么该事件是因为事件 Y=y 的而发生的概率。后验概率指的是将观测值分配到已给定数据的组的概率。先验概率指的是在您收集数据之前数据已划入某个组的概率。
后验概率的计算要以先验概率为基础。后验概率可以根据通过贝叶斯公式,用先验概率和似然函数计算出来
1.4 全概率公式
公式表示若事件A1,A2,…,An构成一个完备事件组且都有正概率,则对任意一个事件B都有公式成立。
1.5 贝叶斯公式
由条件概率公式推导:
结合全概率公式:
公式中,事件的概率为,事件B已发生条件下事件的概率为,事件已发生条件下事件B的概率为。
1.6 贝叶斯公式的意义
后验概率 = 先验概率 x 调整因子
这就是贝叶斯推断的含义。我们先预估一个"先验概率",然后加入实验结果,看这个实验到底是增强还是削弱了"先验概率",由此得到更接近事实的"后验概率"。
2 朴素贝叶斯算法
朴素贝叶斯(Naive Bayes)是一个基于贝叶斯理论的分类器。它会单独考量每一唯独特征被分类的条件概率,进而综合这些概率并对其所在的特征向量做出分类预测。
因此,朴素贝叶斯的基本数据假设是:各个维度上的特征被分类的条件概率之间是相互独立的。它经常被应用在文本分类中,包括互联网新闻的分类,垃圾邮件的筛选。
2.1 公式基础和解释
代表列表,代表特征,是n维的向量,则条件概率——特征为x条件下,属于y类别的概率:
我们不能直接得到,但是通过训练数据集可以得到:
- ,通过预先分好类的训练数据集,计算每个特征的概率分布(预先知道分布模型,常见的如高斯模型,多项式模型,伯努利模型)。
- ,通过预先分好类的训练数据集,计算每个类别的占比
对于不同的分类分母是一样的,所以我们只需知道,概率值最大的分类作为预测分类。
2.2 高斯模型
2.2.1 基本概念
高斯朴素贝叶斯模型是假设条件概率是多元高斯分布,另一方面,由之前的特征的条件独立性假设,我们就可以通过对每个特征的条件概率建模,每个特征的条件概率也服从高斯分布.
高斯分布函数:
特征向量某一维特征的高斯分布函数:
属于某一分类的条件概率分布函数:(每一种分类的每一种特征都有自己的分布参数,公式编辑器无法打出来)
分布函数的参数我们都可以通过训练数据集统计出来。
根据贝叶斯公式:
所以对于高斯模型贝叶斯,所谓的训练就是统计各个分类的每个特征的分布函数参数,得到参数后,可以将特征向量代入,求得各个分类的似然估计,估计值最大的作为预测分类(最大似然估计)。
2.2.2 代码实现(代码来源https://www.jianshu.com/p/807aa6e828a9)
# Example of Naive Bayes implemented from Scratch in Python
import csv
import random
import math
def loadCsv(filename):
lines = csv.reader(open(filename, "rt", encoding="UTF-8-sig"))
dataset = list(lines)
for i in range(len(dataset)):
dataset[i] = [float(x) for x in dataset[i]]
return dataset
def splitDataset(dataset, splitRatio):
trainSize = int(len(dataset) * splitRatio)
trainSet = []
copy = list(dataset)
while len(trainSet) < trainSize:
index = random.randrange(len(copy))
trainSet.append(copy.pop(index))
return [trainSet, copy]
#基于类别分开数据
def separateByClass(dataset):
separated = {}
for i in range(len(dataset)):
vector = dataset[i]
#.eg:6,148,72,35,0,33.6,0.627,50,1
#最后一个元素指示是否患病
if (vector[-1] not in separated):
separated[vector[-1]] = []
separated[vector[-1]].append(vector)
return separated
def mean(numbers):
return sum(numbers) / float(len(numbers))
def stdev(numbers):
avg = mean(numbers)
variance = sum([pow(x - avg, 2) for x in numbers]) / float(len(numbers) - 1)
return math.sqrt(variance)
# 函数将每一个属性的平均值和标准差组合起来了
def summarize(dataset):
# zip 函数将每一个属性的平均值和标准差组合起来了
# 与 zip 相反,可理解为解压,为zip的逆过程,可用于矩阵的转置 --- >>> 转置
# for attribute in zip(*dataset):
# print(attribute)
# 每一行代表一个属性,有几个属性就有几行
# 计算均值和标注差
summaries = [(mean(attribute), stdev(attribute)) for attribute in zip(*dataset)]
del summaries[-1]
return summaries
def summarizeByClass(dataset):
# 先将同一个类别的数据放在一起。然后计算每一个属性的摘要
separated = separateByClass(dataset)
summaries = {}
# 分类别类别(是否得病)计算均值和标准差
for classValue, instances in separated.items():
# 计算平均值和标准差(均值,标准差),每一个属性都有
summaries[classValue] = summarize(instances)
return summaries
# 据摘要中我们已经知道了高斯分布的平均值和方差,而且知道了某一个属性值属于某一个类别的似然
def calculateProbability(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
# 计算某一个属性的值属于每一个类别的概率了
# summaries = {0:[(1, 0.5)], 1:[(20, 5.0)]}
# inputVector = [1.1, '?']
def calculateClassProbabilities(summaries, inputVector):
probabilities = {}
for classValue, classSummaries in summaries.items():
probabilities[classValue] = 1
# classSummaries 包含所有属性的均值和标准差
for i in range(len(classSummaries)):
mean, stdev = classSummaries[i]
x = inputVector[i]
# 给定数据的概率通过连乘所有的属性概率得到,结果是一个词典包含了属性值和对应的概率。
# ---->计算所有类别的联合概率
probabilities[classValue] *= calculateProbability(x, mean, stdev)
return probabilities
def predict(summaries, inputVector):
#计算每个类别的概率
probabilities = calculateClassProbabilities(summaries, inputVector)
bestLabel, bestProb = None, -1
#找出概率最大的标签
for classValue, probability in probabilities.items():
if bestLabel is None or probability > bestProb:
bestProb = probability
bestLabel = classValue
return bestLabel
def getPredictions(summaries, testSet):
predictions = []
for i in range(len(testSet)):
result = predict(summaries, testSet[i])
predictions.append(result)
return predictions
def getAccuracy(testSet, predictions):
correct = 0
for i in range(len(testSet)):
if testSet[i][-1] == predictions[i]:
correct += 1
return (correct / float(len(testSet))) * 100.0
def main():
filename = 'pima-indians-diabetes.data.csv'
splitRatio = 0.67
dataset = loadCsv(filename)
trainingSet, testSet = splitDataset(dataset, splitRatio)
print("Split {0} rows into train={1} and test={2} rows".format(len(dataset), len(trainingSet), len(testSet)))
# prepare model
# 计算每个属性的均值和标准差
summaries = summarizeByClass(trainingSet)
# test model
predictions = getPredictions(summaries, testSet)
accuracy = getAccuracy(testSet, predictions)
print("Accuracy: {0}%".format(accuracy))
main()