朴素贝叶斯定理
原理请参考:
https://www.cnblogs.com/TimVerion/p/11197043.html
即 后验概率 = 先验概率 * 调整因子
在分类中, 先验概率指样本中该类别占所有类别的概率, 调整因子则是每个样本特征的概率乘积, 举个例子.
帅不帅 | 性格 | 上进不 | 值不值得交朋友 | |
---|---|---|---|---|
帅 | 好 | 不上进 | 不值得 | |
不帅 | 不好 | 不上进 | 不值得 | |
帅 | 好 | 上进 | 值得 | |
不帅 | 好 | 上进 | 值得 |
这里的先验概率就是指: 值得交朋友(1/2) , 不值得交朋友(1/2)
调整因子是指你要预测的样本的特征概率, 如果有一个样本是不帅 | 好 | 不上进(例子特征不分散, 因为只有两个值, 我们先不管这个)
那么值得交的后验概率 = 1/2 * 调整因子 = 0, 调整因子 = 不帅在值得交的数据中占(1/2) * 好在值得占(1) * 不上进在值得占(0)
不值得交的后验概率 = 1/2* 1/2 * 1/2 * 1 = 1/8
所以这个人值不值得交呢, 根据数据是 1/8>0, 那就是不值得交了. 不过因为样本数据较少, 出现某个为 0 的概率, 这就有点问题了, 因为实际不可能概率为 0 的.
平滑参数
所以我们需要引入一个平滑参数, 来使这个值不为 0
那么我们计算概率时不是直接使用: 符合要求的样本 / 总样本, 而是 符合要求的样本 + alpha/(总样本 + 标签类别数或特征类别数 * alpha),alpha 一般取 1.0
即先验概率: 值得交朋友(2 + 1/(4+2 * 1))=1/3 , 不值得交朋友(2 + 1/(4+2 * 1)) = 1/3
而特征概率的计算需要这样计算: 其他先不看, 我们直接看值得交中不上进的概率(也就是先前为 0 的概率)= 0+1/(2 + 21) = 1/4, 注意这里的类别数是指 len(上进, 不上进)
值得交的后验概率: 1/3 1/2 * 3/4 * 1/4 = 1/32
不值得交的后验概率: 1/3 * 1/2 * 1/2 * 3/4 = 1/16
虽然还是不值得交, 但至少值得交的概率不为 0 了. 如果你还不懂的话, 直接看验证码的识别, 然后在回来看这个.
sklearn 中的 API
sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
参数
alpha: 上面说的平滑参数
fit_prior: 是否考虑先验概率, 也就是每个类别所占的比例
class_prior: 给定的先验概率数组
属性
class_log_prior_ : 数组, 维度(n_classes, ), 每个类别的对数概率. n_classes 为类别数量, 比如有 10 个类别, 每个类别样本都是 100 个, 则数组为(In 1/10, In 1/10,...)
intercept_ : 同 class_log_prior_
feature_log_prob_ : 数组, 维度 (n_classes,n_features) 给定一类特征的经验对数概率 P(x_i|y). 没看懂
coef_ : 同 feature_log_prob_
class_count_ : 数组, 维度 (n_classes, ) 每个类别的样本个数
classes_ : 数组, 维度 (n_classes,) 每个类别的标签
feature_count_ : 数组, 形状 (n_classes,n_features) 拟合期间每个 (类, 特征) 遇到的样本数. 没看懂
方法
fit(x, y[, sample_weight]): 使用样本 x 和标签 y 作训练
get_params(deep=True): 获取模型的所有参数, deep 不知道有什么用
partial_fit(x, y[, classes, sample_weight]): 一批一批的训练样本(当样本足够大时)
predict(test_x): 根据样本 test_x, 返回预测 y
predict_proba(test_x): 返回样本 test_x 属于每个类别的概率, 也就是说返回的是维度为 (样本数, k) 的二维数组, 每行一维数组的所有元素和为 1, 数组长度为 k.
score(test_x, y, sample_weight =None): 根据样本 test_x 预测 test_y, 然后对比实际的 y 返回的正确分数, sample_weight 为权重
set_params(**args): 重新设置模型参数
当然还有其他朴素贝叶斯分类或回归器, 区别如下:
特征是离散变量时, 使用多项式模型(MultinomialNB)
当特征是连续变量时, 使用高斯模型(GaussianNB)
伯努利模型 (BernoulliNB) 和多项式模型是一致的, 但要求特征是二值化的(1,0)
生成模型
根据上面的描述可知, 像这种简单验证码, 可以使用多项式模型, 也可以使用伯努利模型, 因为图片已经被二值化.
已知图片是 18x10 的二维数组, 数组的每个元素都是 0,1 之间的数. 我们可以组成 180 个特征, 而验证码都是 0-9 的数字, 所以分类是这样来计算的
假设 180 个特征分别为 x1, x2,...,x180, 标签为 0-9, 每个标签的样本个数都是 120 个
某个样本属于 0 的概率: P(0) = P0(x1)P0(x2)....P0(x180)P 总 (0), P0(x1) 表示 x1 在 0 类别样本中所占的比例 (概率),P 总(0) 表示 0 占总样本的比例 (概率) 即 1/10, 这些值都是可以从训练样本求得.
代码和 KNN 的基本一样, 如下:
- from sklearn import naive_bayes
- import os
- from PIL import Image
- import numpy as np
- def func():
- x = []
- y = []
- for label in os.listdir('train'):
- for file in os.listdir(f'train/{label}'):
- im = Image.open(f'train/{label}/{file}')
- pix = np.array(im)
- pix = (pix> 180) * 1
- pix = pix.ravel()
- x.append(list(pix))
- y.append(int(label))
- train_x = np.array(x)
- train_y = np.array(y)
- model = naive_bayes.MultinomialNB(alpha=1)
- model.fit(train_x, train_y)
- x = []
- y = []
- for label in os.listdir('test'):
- for file in os.listdir(f'test/{label}'):
- im = Image.open(f'test/{label}/{file}')
- pix = np.array(im)
- pix = (pix> 180) * 1
- pix = pix.ravel()
- x.append(list(pix))
- y.append(int(label))
- test_x = np.array(x)
- test_y = np.array(y)
- score = model.score(test_x, test_y)
- return score
- if __name__ == "__main__":
- score = func()
- print(score)
在这种简单验证码识别上, 朴素贝叶斯也可以达到 100% 的正确率. 如果将样本特征改成 16 个的话, 你会发现朴素贝叶斯和 KNN 错误的地方都是一样的, 都是同一个验证码识别成了同一个错误.
最后, 我正在学习一些机器学习的算法, 对于一些我需要记录的内容我都会分享到博客和微信公众号, 欢迎关注. 平时的话一般分享一些爬虫或者 Python 的内容. 另外, 如果博客有错误的话, 还请指出.
这是已标注的数据: https://www.lanzous.com/i8epywd
最后, 我正在学习一些机器学习的算法, 对于一些我需要记录的内容我都会分享到博客和微信公众号(python 成长路), 欢迎关注. 平时的话一般分享一些爬虫或者 Python 的内容.
来源: https://www.cnblogs.com/kanadeblisst/p/12167477.html