, n维向量的集合
是空间
上的随机向量
是输出空间
上的随机变量
由
联合概率分布 独立同分布产生
目标 :通过训练数据集学习 联合概率分布
上面两项相乘即可得到联合概率
但是
有 指数级 数量的参数,如果
的取值有
个,
,
可取值有
个,总的参数个数为
, 不可行
做出 条件独立性假设 :
之间独立
朴素贝叶斯法实际上学习到生成数据的机制,所以属于生成模型。条件独立假设等于是说用于分类的特征在类确定的条件下都是条件独立的。这一假设使朴素贝叶斯法变得简单,但有时会牺牲一定的分类准确率。
朴素贝叶斯法分类时,对给定的输入
,通过学习到的模型计算后验概率分布
,将后验概率最大的类作为
的类输出。
推导 :
贝叶斯定理
将(1)代入(2)有:
所以 朴素贝叶斯分类器表示为:
上式中,分母对所有的
都是相同的,所以
设第
个特征
可能的取值为
, 条件概率的极大似然估计为:
是第
个样本的第
个特征;
是第
个特征可能的第
个值,
是指示函数
朴素贝叶斯算法:
输入:
,
是第
个样本的第
个特征
,
是第
个特征可能的第
个值,
输出:
的分类
步骤:
, 计算
的类
例题: 用下表训练数据学习一个贝叶斯分类器并确定
的类标记
。
为特征,取值的集合分别为
,
为类标记,
。
训练数据 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
X(1)X^{(1)}X(1) | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 |
X(2)X^{(2)}X(2) | S | M | M | S | S | S | M | M | L | L | L | M | M | L | L |
YYY | -1 | -1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 |
1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
S M M S S S M M L L L M M L L
-1 -1 1 1 -1 -1 -1 1 1 1 1 1 1 1 -1
解: 先验概率
条件概率
对给定的
计算:
时:
时:
时的概率最大,所以
。
# -*- coding:utf-8 -*-
# Python 3.7
# @Time: 2020/1/19 22:08
# @Author: Michael Ming
# @Website: https://michael.blog.csdn.net/
# @File: naiveBayes.py
import numpy as np
data = [[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3],
['S', 'M', 'M', 'S', 'S', 'S', 'M', 'M', 'L', 'L', 'L', 'M', 'M', 'L', 'L'],
[-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1]]
X1 = []
X2 = []
Y = []
for i in range(len(data[0])): # 统计数据种类
if data[0][i] not in X1:
X1.append(data[0][i])
if data[1][i] not in X2:
X2.append(data[1][i])
if data[2][i] not in Y:
Y.append(data[2][i])
nY = [0] * len(Y)
for i in range(len(data[0])): # 统计Yi的数量
nY[Y.index(data[2][i])] += 1
PY = [0.0] * len(Y)
for i in range(len(Y)):
PY[i] = nY[i] / len(data[0]) # Yi的概率
PX1_Y = np.zeros((len(X1), len(Y))) # 条件概率
PX2_Y = np.zeros((len(X2), len(Y)))
for i in range(len(data[0])):
PX1_Y[X1.index(data[0][i])][Y.index(data[2][i])] += 1 # 统计频数
PX2_Y[X2.index(data[1][i])][Y.index(data[2][i])] += 1
for i in range(len(Y)):
PX1_Y[:, i] /= nY[i] # 转成条件概率
PX2_Y[:, i] /= nY[i]
x = [2, 'S']
PX_Y = [PX1_Y, PX2_Y]
X = [X1, X2]
ProbY = [0.0] * len(Y)
for i in range(len(Y)):
ProbY[i] = PY[i]
for j in range(len(x)):
ProbY[i] *= PX_Y[j][X[j].index(x[j])][i]
maxProb = -1
idx = -1
for i in range(len(Y)): # 取最大的概率
if ProbY[i] > maxProb:
maxProb = ProbY[i]
idx = i
print(Y)
print(ProbY)
print(x, ", 最有可能对应的贝叶斯估计 y = %d" % (Y[idx]))
# 运行结果
[-1, 1]
[0.06666666666666667, 0.02222222222222222]
[2, 'S'] , 最有可能对应的贝叶斯估计 y = -1
用极大似然估计可能会出现所要估计的概率值为0的情况。会影响到后验概率的计算结果,使分类产生偏差。解决方法是采用贝叶斯估计。
条件概率的贝叶斯估计:
式中
, 取 0 时,就是极大似然估计; 取正数,对随机变量各个取值的频数上赋予一个正数; 常取
,这时称为 拉普拉斯平滑(Laplacian smoothing)
先验概率的贝叶斯估计:
例题:(与上面一致,采用拉普拉斯平滑估计概率,取
) 用下表训练数据学习一个贝叶斯分类器并确定
的类标记
。
为特征,取值的集合分别为
,
为类标记,
。
训练数据 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
X(1)X^{(1)}X(1) | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 |
X(2)X^{(2)}X(2) | S | M | M | S | S | S | M | M | L | L | L | M | M | L | L |
YYY | -1 | -1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 |
1 1 1 1 1 2 2 2 2 2 3 3 3 3 3
S M M S S S M M L L L M M L L
-1 -1 1 1 -1 -1 -1 1 1 1 1 1 1 1 -1
解: 先验概率
条件概率
对给定的
计算:
时:
时:
时的概率最大,所以
。
# -*- coding:utf-8 -*-
# Python 3.7
# @Time: 2020/1/19 22:08
# @Author: Michael Ming
# @Website: https://michael.blog.csdn.net/
# @File: naiveBayes.py
import numpy as np
data = [[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3],
['S', 'M', 'M', 'S', 'S', 'S', 'M', 'M', 'L', 'L', 'L', 'M', 'M', 'L', 'L'],
[-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1]]
X1 = []
X2 = []
Y = []
for i in range(len(data[0])): # 统计数据种类
if data[0][i] not in X1:
X1.append(data[0][i])
if data[1][i] not in X2:
X2.append(data[1][i])
if data[2][i] not in Y:
Y.append(data[2][i])
nY = [0] * len(Y)
for i in range(len(data[0])): # 统计Yi的数量
nY[Y.index(data[2][i])] += 1
PY = [0.0] * len(Y)
for i in range(len(Y)):
PY[i] = (nY[i]+1) / (len(data[0])+len(Y)) # Yi的概率,+1为平滑
PX1_Y = np.zeros((len(X1), len(Y))) # 条件概率
PX2_Y = np.zeros((len(X2), len(Y)))
for i in range(len(data[0])):
PX1_Y[X1.index(data[0][i])][Y.index(data[2][i])] += 1 # 统计频数
PX2_Y[X2.index(data[1][i])][Y.index(data[2][i])] += 1
for i in range(len(Y)):
PX1_Y[:, i] = (PX1_Y[:, i] + 1)/(nY[i]+len(X1)) # 转成条件概率,带平滑
PX2_Y[:, i] = (PX2_Y[:, i] + 1)/(nY[i]+len(X2))
x = [2, 'S']
PX_Y = [PX1_Y, PX2_Y]
X = [X1, X2]
ProbY = [0.0] * len(Y)
for i in range(len(Y)):
ProbY[i] = PY[i]
for j in range(len(x)):
ProbY[i] *= PX_Y[j][X[j].index(x[j])][i]
maxProb = -1
idx = -1
for i in range(len(Y)): # 取最大的概率
if ProbY[i] > maxProb:
maxProb = ProbY[i]
idx = i
print(Y)
print(ProbY)
print(x, ", 最有可能对应的贝叶斯估计 y = %d" % (Y[idx]))
# 运行结果
[-1, 1]
[0.06100217864923746, 0.0326797385620915]
[2, 'S'] , 最有可能对应的贝叶斯估计 y = -1
特征的概率分布假设为高斯分布
概率密度函数:
数学期望(mean):
,方差:
抄自:https://github.com/fengdu78/lihang-code,并修复其中一个Bug
import math
class GausNB():
def __init__(self):
self.model = None
@staticmethod
def mean(X): # 均值
return sum(X) / float(len(X))
def std(self, X): # 标准差
avg = self.mean(X)
return np.sqrt(sum([pow(x - avg, 2) for x in X]) / float(len(X)))
def gaus_prob(self, x, mean, std): # 高斯概率密度
exponent = math.exp(-(math.pow(x - mean, 2) / (2 * math.pow(std, 2))))
return (1 / (math.sqrt(2 * math.pi) * std)) * exponent
def summarize(self, train_data):
summaries = [(self.mean(i), self.std(i)) for i in zip(*train_data)]
return summaries # 返回 [(各特征的均值,标准差),(),()...]]
def fit(self, X, y):
labels = list(set(y))
data = {label: [] for label in labels}
for x, label in zip(X, y):
data[label].append(x)
self.model = {
label: [len(data[label]) / float(len(X)), self.summarize(value)]
for label, value in data.items()
} # model写入字典 label : [[label概率],[(各特征的均值,标准差),(),()...]]
return 'GuassNB train Done !'
def cal_prob(self, input_data):
prob = {}
for label, value in self.model.items():
prob[label] = value[0] # P(Y=Ck), 此处修正了原作者的初始概率均等问题
for i in range(len(value[1])):
mean, std = value[1][i]
prob[label] *= self.gaus_prob(input_data[i], mean, std)
# 分类器概率公式
return prob
def predict(self, X_test):
label = sorted(self.cal_prob(X_test).items(), key=lambda x: x[-1])[-1][0]
# {label : prob},按照概率排序,取最后(最大)的【0】标签
return label
def predict_prob(self, X_test):
prob = sorted(self.cal_prob(X_test).items(), key=lambda x: x[-1])[-1][1]
s = sum(i for i in self.cal_prob(X_test).values())
return prob / s # 预测概率
def score(self, X_test, y_test):
right = 0
for X, y in zip(X_test, y_test):
label = self.predict(X)
if label == y:
right += 1
return right / float(len(X_test))
clf = GausNB()
clf.fit(X_train, y_train)
x = [2, ord('S')]
print(x, "自编程高斯贝叶斯预测", clf.predict(x), clf.predict_prob(x))
[2, 83] 自编程高斯贝叶斯预测 -1 0.9221912681158962
import pandas as pd
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import BernoulliNB
from sklearn.naive_bayes import MultinomialNB
for i in range(len(data[0])):
data[1][i] = ord(data[1][i]) # 将字符转成ASCII数字
data = np.array(pd.DataFrame(data).T)
X_train, y_train = data[:, :-1], data[:, -1]
clf = GaussianNB()
clf.fit(X_train, y_train)
print(x, "的高斯贝叶斯预测是", clf.predict([[2, ord('S')]]), clf.predict_proba([[2, ord('S')]]))
clf = BernoulliNB()
clf.fit(X_train, y_train)
print(x, "的伯努利贝叶斯预测是", clf.predict([[2, ord('S')]]), clf.predict_proba([[2, ord('S')]]))
clf = MultinomialNB()
clf.fit(X_train, y_train)
print(x, "的多项式贝叶斯预测是", clf.predict([[2, ord('S')]]), clf.predict_proba([[2, ord('S')]]))
[2, 'S'] 的高斯贝叶斯预测是 [-1] [[0.92219127 0.07780873]]
[2, 'S'] 的伯努利贝叶斯预测是 [1] [[0.38180179 0.61819821]]
[2, 'S'] 的多项式贝叶斯预测是 [1] [[0.41221915 0.58778085]]