学习《scikit-learn机器学习》时的一些实践。
条件独立
朴素即指的是条件独立假设,假设n个特征之间不相关,则可据联合概率的条件展开式:
将其中的
变为
从而,朴素贝叶斯下的联合概率可展开为:
右侧的每一项都可从数据集中统计出来,因此可通过计算和比较联合概率来比较后验概率,以对类别做判断。
对于连续的特征值,可以通过区间划分形成离散值。但对于小数据集,这样做的偏差太大。可以通过考虑该特征作为随机变量的概率分布,计算其统计量并放入相应的概率分布函数模型中做计算。如计算方差 和均值 便可得到正态分布的概率密度函数。
概率分布
概率分布是描述随机变量的概率规律。
PDF和PMF
概率密度函数(PDF)用于描述连续型随机变量在某个特定值的可能性,概率质量函数(PMF)用于描述离散型随机变量在某个特定值的可能性。
伯努利分布
即零一分布、两点分布,意在非黑即白:
类别分布
不止两种情况,即可能有多种情况:
二项式分布
即将伯努利实验(符合伯努利分布的实验)重复
次,结果概率为
的事件出现
次的概率:
当实验只做一次时,二项式分布退化为伯努利分布。
多项式分布
满足类别分布(即有多种情况)的实验,连续做n次后,每种类别出现的特定次数组合的概率分布情况。
表示类别
出现的次数,
表示类别
在单次实验(即类别分布)中出现的概率。
作者给出一个易懂的理解,将后面的
视为按特定顺序出现的所有类别的一个排列的概率,前面的系数将排列变成任意次序的组合。
多项式分布式二项式分布在类别数上的推广(两类变多类),也是类别分布在重复次数上的推广(一次变多次)。
TF-IDF
使用 衡量词在文档中的重要程度。
词频TF
特定词语在这篇文章中出现次数除以文档的词语总数。衡量词语对文档的重要程度,因为某词出现的频率较高则可能对该文档有标定意义。
逆文档频率指数IDF
总文档数目除以包含该词语的文档数目,再取对数。表达词语的权重指数,因为某词的出现很广泛则很可能是一个泛用词,对特定的文档没有标定意义。
朴素贝叶斯做文档分类
from sklearn.datasets import load_files
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from matplotlib import pyplot as plt
# 读取数据,这里的数据文件每一类在一个子目录中,子目录的名字即是文档的类别
news_train = load_files(r"E:\Data\code\datasets\mlcomp\379\train")
print("共{}文档分为{}类".format(len(news_train.data), len(news_train.target_names)))
# data中存的是所有文档,target中存的是类别号,若要知道类别名,在target_names中查询
print("0号文档的类别名:", news_train.target_names[news_train.target[0]])
共13180文档分为20类
0号文档的类别名: talk.politics.misc
# 转化为由TF-IDF表达的权重信息构成的向量
vectorizer = TfidfVectorizer(encoding='latin-1')
# 相当于先fit(完成语料分析,提取词典),再transform(把每篇文档转化为向量以构成矩阵)
X_train = vectorizer.fit_transform((d for d in news_train.data))
y_train = news_train.target
print("样本数:%d,特征数%d" % X_train.shape)
print("样本{}中的非零特征数为{}".format(news_train.filenames[0], X_train[0].getnnz()))
样本数:13180,特征数130274
样本E:\Data\code\datasets\mlcomp\379\train\talk.politics.misc\17860-178992中的非零特征数为108
# 多项式分布的朴素贝叶斯.其中alpha是平滑参数,越小越容易造成过拟合
clf = MultinomialNB(alpha=0.001)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
print("训练集得分:", train_score)
训练集得分: 0.9974203338391502
# 加载测试集
news_test = load_files(r"E:\Data\code\datasets\mlcomp\379\test")
print("共{}文档分为{}类".format(len(news_train.data), len(news_train.target_names)))
共13180文档分为20类
# 对测试集进行向量化,前面的语料分析和提取词典是基于训练集的,这里只调用transform
X_test = vectorizer.transform((d for d in news_test.data))
y_test = news_test.target
print("样本数:%d,特征数%d" % X_train.shape)
样本数:5648,特征数130274
# 尝试预测第一篇文档
pred = clf.predict(X_test[0])
print("预测为:{},实际是:{}".format(pred[0], news_test.target[0]))
预测为:7,实际是:7
# 在整个测试集上做预测
pred = clf.predict(X_test)
# 查看对每个类别的预测准确性
print("使用的分类器是", clf, "分类表现如下")
print(classification_report(y_test, pred, target_names=news_test.target_names))
# 生成混淆矩阵
cm = confusion_matrix(y_test, pred)
print("混淆矩阵:\n", cm)
如第1行第20列的13,即表示类别为0的文档有13个被分到类别19。对角线上的数字都是正确分类的(行列相同,即分类到自己)。
# 混淆矩阵可视化
plt.figure(figsize=(8, 8), dpi=144)
plt.title("混淆矩阵")
ax = plt.gca() # Get Current Axes
ax.spines['right'].set_color('none') # ax.spines是数据区域的边界
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.xaxis.set_ticks_position('none') # 删除轴上的刻度点
ax.yaxis.set_ticks_position('none')
ax.set_xticklabels([])
ax.set_yticklabels([])
plt.matshow(cm, fignum=1, cmap='gray') # plt.matshow专门用于矩阵可视化
plt.colorbar() # 添加渐变色条
plt.show()