本菜鸡最近想学学 机器学习
,这不,学到了 朴素贝叶斯。
如果觉得我这篇文章写的好的话,能不能给我 点个赞
,评论
一波。如果要点个 关注
的话也不是不可以
对于 分类算法 来说,一般可分为 生成类算法 和 判别类算法 。
通俗来讲,这类算法是在给定数据为 各个特征某一取值 的情况下,求出 属于标签某种取值 的概率,这类算法的典型是 朴素贝叶斯。
通俗来讲,这类算法是 给定一些特征值,按照 各特征对标签值的影响程度,判断属于哪一类数据,这类算法的典型是 决策树。下一篇文章会讲到。
生成类算法 注重 特征值组合对标签值的影响;而 判别类算法 注重 单个特征对标签值的影响 。
假设有两个事件 A
和 B
,出现的概率分别为 P(A)
和 P(B)
,两个事件同时出现 的概率为 P ( A , B ) P(A, B) P(A,B)。那么,在事件 A
发生的条件下,事件 B
发生的概率可以表示为 P(B|A)
,计算公式为
P ( B ∣ A ) = P ( A , B ) P ( A ) = P ( A ∣ B ) ⋅ P ( B ) P ( A ) P(B|A) = \frac{P(A, B)}{P(A)}=\frac{P(A|B) \cdot P(B)}{P(A)} P(B∣A)=P(A)P(A,B)=P(A)P(A∣B)⋅P(B)
一般来说
P(B|A) ≠ P(A)
,也就是 A
和 B
不是相互独立的,事件 B
的发生对事件 A
的发生 有影响。
P(B|A) > P(A)
, 说明事件 B
的发生对事件 A
的发生有 促进 作用。B
的发生对事件 A
的发生 没有影响 。朴素贝叶斯 中我们认为 特征之间 是 相互独立 的,目的是在 各个特征值组合 的条件下,预测 标签各值 出现的概率。
假设数据集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) … ( x n , y n ) } T=\{(x_1, y_1), (x_2, y_2) \dots (x_n, y_n)\} T={(x1,y1),(x2,y2)…(xn,yn)} 由 P(X, Y)
独立同分布 产生,其中 X
和 Y
是两个特征,则
Y
取值为 c k c_k ck 的条件下, 特征 X
取值为 x
的概率,表示为 P(X=x|Y=c_k)
,计算公式如下:P ( X = x ∣ Y = c k ) = P ( X 1 = x 1 , X 2 = x 2 , … , X n = x n ∣ Y = c k ) , k = 1 , 2 , … , K P(X=x|Y=c_k) = P(X_1=x_1, X_2=x_2, \dots , X_n=x_n|Y=c_k), \: k=1,2,\dots,K P(X=x∣Y=ck)=P(X1=x1,X2=x2,…,Xn=xn∣Y=ck),k=1,2,…,K
在 条件独立性 假设下,可以合为
P ( X = x ∣ Y = c k ) = ∏ j = 1 n P ( X j = x j ∣ Y = c k ) P(X=x|Y=c_k) = \prod \limits_{j=1}^{n}{P(X_j=x_j|Y=c_k)} P(X=x∣Y=ck)=j=1∏nP(Xj=xj∣Y=ck) 。
X
取值为 x
的条件下,特征 Y
取值为 c k c_k ck 的概率,表示为 P(Y=c_k|X=x)
,计算公式如下:P ( Y = c k ∣ X = x ) = P ( X = x , Y = c k ) P ( X = x ) = P ( Y = c k ) ⋅ P ( X = x ∣ Y = c k ) P ( X = x ) = P ( Y = c k ) ⋅ ∏ j = 1 n P ( X j = x j ∣ Y = c k ) ∑ k P ( Y = c k ) ⋅ ∏ j = 1 n P ( X j = x j ∣ Y = c k ) P(Y=c_k|X=x) = \frac{P(X=x, Y=c_k)}{P(X=x)}=\frac{P(Y=c_k) \cdot P(X=x|Y=c_k)}{P(X=x)} \\ =\frac{P(Y=c_k) \cdot \prod \limits_{j=1}^{n}{P(X_j=x_j|Y=c_k)}}{\displaystyle \sum _{k}{P(Y=c_k) \cdot \prod \limits_{j=1}^{n}{P(X_j=x_j|Y=c_k)}}} P(Y=ck∣X=x)=P(X=x)P(X=x,Y=ck)=P(X=x)P(Y=ck)⋅P(X=x∣Y=ck)=k∑P(Y=ck)⋅j=1∏nP(Xj=xj∣Y=ck)P(Y=ck)⋅j=1∏nP(Xj=xj∣Y=ck)
朴素贝叶斯 最后求得就是 每个标签值 的 后验概率,将结果预测为 后验概率最大 的标签值。
假如我们有这样一个数据集(自己造的),如 下表:
序号 | x1 | x2 | y |
---|---|---|---|
1 | 小 | 少 | 0 |
2 | 小 | 中 | 0 |
3 | 小 | 中 | 1 |
4 | 小 | 少 | 1 |
5 | 小 | 少 | 0 |
6 | 中 | 少 | 0 |
7 | 中 | 中 | 0 |
8 | 中 | 中 | 1 |
9 | 中 | 多 | 1 |
10 | 中 | 多 | 1 |
11 | 大 | 多 | 1 |
12 | 大 | 中 | 1 |
13 | 大 | 中 | 1 |
14 | 大 | 多 | 1 |
15 | 大 | 多 | 0 |
其中,
如果有一个人 年龄中等,收入少,那他 是否被诈骗过 ?
这就需要用到 贝叶斯 来判断。
先验概率
P ( Y = 1 ) = 9 15 , P ( Y = 0 ) = 6 15 P ( x 1 = 中 ) = 5 15 , P ( x 2 = 少 ) = 4 15 P ( x 1 = 中 , x 2 = 少 ) = P ( x 1 = 中 ) × P ( x 2 = 少 ) = 4 45 P(Y=1)=\frac{9}{15},\: P(Y=0)=\frac{6}{15} \\ P(x_1=中)=\frac{5}{15},\: P(x_2=少)=\frac{4}{15} \\ P(x_1=中,x_2=少)=P(x_1=中) \times P(x_2=少)=\frac{4}{45} P(Y=1)=159,P(Y=0)=156P(x1=中)=155,P(x2=少)=154P(x1=中,x2=少)=P(x1=中)×P(x2=少)=454
条件概率(假设 特征之间相互独立)
P ( x 1 = 中 ∣ Y = 0 ) = 2 6 , P ( x 1 = 中 ∣ Y = 1 ) = 3 9 P ( x 2 = 少 ∣ Y = 0 ) = 3 6 , P ( x 2 = 少 ∣ Y = 1 ) = 1 9 P ( x 1 = 中 , x 2 = 少 ∣ Y = 0 ) = P ( x 1 = 中 ∣ Y = 0 ) × P ( x 2 = 少 ∣ Y = 0 ) = 1 6 P ( x 1 = 中 , x 2 = 少 ∣ Y = 1 ) = P ( x 1 = 中 ∣ Y = 1 ) × P ( x 2 = 少 ∣ Y = 1 ) = 1 27 P(x_1=中|Y=0)=\frac{2}{6},\: P(x_1=中|Y=1)=\frac{3}{9} \\ P(x_2=少|Y=0)=\frac{3}{6}, P(x_2=少|Y=1)=\frac{1}{9} \\ P(x_1=中,x_2=少|Y=0)=P(x_1=中|Y=0) \times P(x_2=少|Y=0)=\frac{1}{6} \\ P(x_1=中,x_2=少|Y=1)=P(x_1=中|Y=1) \times P(x_2=少|Y=1)=\frac{1}{27} P(x1=中∣Y=0)=62,P(x1=中∣Y=1)=93P(x2=少∣Y=0)=63,P(x2=少∣Y=1)=91P(x1=中,x2=少∣Y=0)=P(x1=中∣Y=0)×P(x2=少∣Y=0)=61P(x1=中,x2=少∣Y=1)=P(x1=中∣Y=1)×P(x2=少∣Y=1)=271
后验概率
P ( Y = 0 ∣ x 1 = 中 , x 2 = 少 ) = P ( x 1 = 中 , x 2 = 少 ∣ Y = 0 ) × P ( Y = 0 ) P ( x 1 = 中 , x 2 = 少 ) = 1 6 × 6 15 4 45 = 3 4 P ( Y = 1 ∣ x 1 = 中 , x 2 = 少 ) = P ( x 1 = 中 , x 2 = 少 ∣ Y = 1 ) × P ( Y = 1 ) P ( x 1 = 中 , x 2 = 少 ) = 1 27 × 9 15 4 45 = 1 4 P(Y=0|x_1=中,x_2=少)=\frac{P(x_1=中,x_2=少|Y=0) \times P(Y=0)}{P(x_1=中,x_2=少)}=\frac{\frac{1}{6} \times \frac{6}{15}}{\frac{4}{45}}=\frac{3}{4} \\ P(Y=1|x_1=中,x_2=少)=\frac{P(x_1=中,x_2=少|Y=1) \times P(Y=1)}{P(x_1=中,x_2=少)}=\frac{\frac{1}{27} \times \frac{9}{15}}{\frac{4}{45}}=\frac{1}{4} P(Y=0∣x1=中,x2=少)=P(x1=中,x2=少)P(x1=中,x2=少∣Y=0)×P(Y=0)=45461×156=43P(Y=1∣x1=中,x2=少)=P(x1=中,x2=少)P(x1=中,x2=少∣Y=1)×P(Y=1)=454271×159=41
∵ P ( Y = 0 ∣ x 1 = 中 , x 2 = 少 ) > P ( Y = 1 ∣ x 1 = 中 , x 2 = 少 ) ∴ 这 个 人 很 大 概 率 没 有 被 骗 过 。 \because P(Y=0|x_1=中,x_2=少) > P(Y=1|x_1=中,x_2=少) \\ \therefore 这个人很大概率 \: 没有被骗过 \: 。 ∵P(Y=0∣x1=中,x2=少)>P(Y=1∣x1=中,x2=少)∴这个人很大概率没有被骗过。
from collections import Iterable
class NaiveBayes:
def __init__(self):
# 先验概率
self.pri = pd.DataFrame()
# 条件概率
self.cond = pd.DataFrame()
# 标签列,默认为最后一列
self.y_col = ''
# 特征列名列表
self.featrues = []
def get_frequency(self, data, name=None, key=None):
# 获得频率
freq = data.value_counts(normalize=True)
# 设置返回的 dataframe 的列名和索引
name = freq.name if name is None else name
key = freq.name if key is None else key
freq = freq.to_frame(name=name)
freq.index = pd.MultiIndex.from_product([[key], freq.index.tolist()])
return freq
def get_priori(self, data):
# 初始化结果
result = pd.DataFrame()
# 遍历特征列
for column in data.columns:
# 获得频率
p = self.get_frequency(data[column], 'value')
# 保存结果
result = result.append(p)
# 返回先验概率
return result
def get_conditional(self, data):
# 初始化结果
result = None
# 以标签列分类
for cate, cate_index in data.groupby(self.y_col).groups.items():
# 每个标签取值对应的数据
x = data.loc[cate_index, self.featrues]
# 初始化标签取值对应各特征取值频次,即 P(X=x|Y=y)
cate_df = None
# 遍历特征列
for column in self.featrues:
# 获得对应频次
freq = self.get_frequency(x[column], name=cate, key=column)
# 如果为 None,初始化
if cate_df is None:
cate_df = freq
# 否则,拼接结果
else:
cate_df = pd.concat([cate_df, freq])
# 逻辑同上
if result is None:
result = cate_df
else:
result = pd.concat([result, cate_df], axis=1)
# 返回条件概率
return result
def train(self, data, y_col='y'):
if y_col not in data.columns:
print(f'Column of y named {y_col} not in data. It will go by column {data.columns[-1]}')
y_col = data.columns[-1]
# 设置标签列列名
self.y_col = y_col
# 获得特征列名列表
self.featrues = data.columns.tolist()
self.featrues.remove(y_col)
# 先验概率
self.pri = self.get_priori(data)
# 条件概率
self.cond = self.get_conditional(data)
return
def forward(self, pred_dict):
# 预测结果,每一列,列名为标签各取值,值为各标签值在指定条件下的概率
result = None
# 遍历要预测的特征值字典,获得各标签值概率中 ΠP(X=x)
for key, value in pred_dict.items():
# 如果特征及值不存在,报错
if (key, value) not in self.cond.index:
raise ValueError(f'The key or value of input data not exists.')
# 逻辑类似于 self.get_conditional
if result is None:
result = self.cond.loc[(key, value)].to_frame().T
else:
result *= self.cond.loc[(key, value)]
# 每列乘上 P(Y=y)
result = result.apply(lambda x: x * self.pri.loc[(self.y_col, x.name)].values[0])
result /= result.sum(axis=1).values[0]
return result.iloc[0]
def predict(self, item):
# 判断输入的用于预测的数据是否可迭代
# 是的话就预测,不是的话就报错
if isinstance(item, Iterable):
# 输入特征值个数不对,报错
if len(item) != len(self.featrues):
raise ValueError(f'The number of input value is [{len(item)}], '
f'which is not equal to the number of featrue [{len(self.featrues)}].')
# 初始化特征值字典
pred_dict = {}
# 如果输入数据为字典,直接覆盖
if isinstance(item, dict):
pred_dict = item
# 否则默认按照列名顺序传值
else:
for i, v in enumerate(item):
if isinstance(i, dict):
pred_dict.update(v)
else:
pred_dict[self.featrues[i]] = v
# 返回预测结果
return self.forward(pred_dict).idxmax()
else:
raise TypeError(f'The type of input data [{type(item)}] is not iterable.')
测试一下(data
如 上表):
Input[]: model = NaiveBayes()
model.train(data)
x_pred = {'x1': '中', 'x2': '少'}
prediction = model.predict(x_pred)
print(f'Value: {", ".join([f"{key}: {value}" for key, value in x_pred.items()])}. Prediction: {prediction}')
-------------------------------------------------------------------
Output[]: Value: x1: 中, x2: 少. Prediction: 0
预测结果正确!!!
sklearn
Input[]: import numpy as np
from sklearn import preprocessing
from sklearn.naive_bayes import GaussianNB
encoders = {}
for column in train_data:
if train_data[column].dtype == object:
encoders[column] = preprocessing.LabelEncoder()
train_data[column] = encoders[column].fit_transform(train_data[column])
model = GaussianNB()
model.fit(train_data[train_data.columns[:-1]], train_data['y'])
model.predict(np.array([encoders[key].transform([value])[0] for key, value in x_pred.items()]).reshape(1, -1))
-------------------------------------------------------------------
Output[]: array([0], dtype=int64)
其中,train_data
如 上表。
上边的例子就是使用 朴素贝叶斯 算法进行 分类。
有想要一起学习 python
的小伙伴可以 私信我
进群哦。
以上就是我要分享的内容,因为学识尚浅,会有不足,还请各位大佬指正。
有什么问题也可在评论区留言。