朴素贝叶斯分类最适合的场景就是文本分类、情感分析和垃圾邮件识别。其中情感分析和垃圾邮件识别都是通过文本来进行判断。从这里你能看出来,这三个场景本质上都是文本分类,这也是朴素贝叶斯最擅长的地方。所以朴素贝叶斯也常用于自然语言处理NLP的工具。
今天我带你一起使用朴素贝叶斯做下文档分类的项目,最重要的工具就是sklearn这个机器学习神器。
sklearn机器学习包
sklearn的全称叫Scikit-learn,它给我们提供了3个朴素贝叶斯分类算法,分别是高斯朴素贝叶斯(GaussianNB)、多项式朴素贝叶斯(MultinomialNB)和伯努利朴素贝叶斯(BernoulliNB)。
这三种算法适合应用在不同的场景下,我们应该根据特征变量的不同选择不同的算法:
高斯朴素贝叶斯:特征变量是连续变量,符合高斯分布,比如说人的身高,物体的长度。
多项式朴素贝叶斯:特征变量是离散变量,符合多项分布,在文档分类中特征变量体现在一个单词出现的次数,或者是单词的TF-IDF值等。
伯努利朴素贝叶斯:特征变量是布尔变量,符合0/1分布,在文档分类中特征是单词是否出现。
伯努利朴素贝叶斯是以文件为粒度,如果该单词在某文件中出现了即为1,否则为0。而多项式朴素贝叶斯是以单词为粒度,会计算在某个文件中的具体次数。而高斯朴素贝叶斯适合处理特征变量是连续变量,且符合正态分布(高斯分布)的情况。比如身高、体重这种自然界的现象就比较适合用高斯朴素贝叶斯来处理。而文本分类是使用多项式朴素贝叶斯或者伯努利朴素贝叶斯。
什么是TF-IDF值呢?
我在多项式朴素贝叶斯中提到了“词的TF-IDF值”,如何理解这个概念呢?
TF-IDF是一个统计方法,用来评估某个词语对于一个文件集或文档库中的其中一份文件的重要程度。
TF-IDF实际上是两个词组Term Frequency和Inverse Document Frequency的总称,两者缩写为TF和IDF,分别代表了词频和逆向文档频率。
词频TF计算了一个单词在文档中出现的次数,它认为一个单词的重要性和它在文档中出现的次数呈正比。
逆向文档频率IDF,是指一个单词在文档中的区分度。它认为一个单词出现在的文档数越少,就越能通过这个单词把该文档和其他文档区分开。IDF越大就代表该单词的区分度越大。
所以TF-IDF实际上是词频TF和逆向文档频率IDF的乘积。这样我们倾向于找到TF和IDF取值都高的单词作为区分,即这个单词在一个文档中出现的次数多,同时又很少出现在其他文档中。这样的单词适合用于分类。
TF-IDF如何计算
首先我们看下词频TF和逆向文档概率IDF的公式。
词频TF=单词出现的次数/该文档的总单词数
逆向文档频率IDF=log(文档总数)/(该单词出现的文档数+1)
为什么IDF的分母中,单词出现的文档数要加1呢?因为有些单词可能不会存在文档中,为了避免分母为0,统一给单词出现的文档数都加1。
TF-IDF=TF*IDF。
你可以看到,TF-IDF值就是TF与IDF的乘积,这样可以更准确地对文档进行分类。比如“我”这样的高频单词,虽然TF词频高,但是IDF值很低,整体的TF-IDF也不高。
我在这里举个例子。假设一个文件夹里一共有10篇文档,其中一篇文档有1000个单词,“this”这个单词出现20次,“bayes”出现了5次。“this”在所有文档中均出现过,而“bayes”只在2篇文档中出现过。我们来计算一下这两个词语的TF-IDF值。
针对“this”,计算TF-IDF值:
词频TF =20/1000=0.02
逆向文档频率 IDF=log(10/(10+1))=-0.0414
所以TF-IDF=0.02*(-0.0414)=-8.28e-4。
针对“bayes”,计算TF-IDF值:
词频TF =5/1000=0.005
逆向文档频率 IDF=log(10/(2+1))=0.5229
TF-IDF=0.005*0.5229=2.61e-3。
很明显“bayes”的TF-IDF值要大于“this”的TF-IDF值。这就说明用“bayes”这个单词做区分比单词“this”要好。
如何求TF-IDF
在sklearn中我们直接使用TfidfVectorizer类,它可以帮我们计算单词TF-IDF向量的值。在这个类中,取sklearn计算的对数log时,底数是e,不是10。
下面我来讲下如何创建TfidfVectorizer类。
TfidfVectorizer类的创建:
创建TfidfVectorizer的方法是:
1 | TfidfVectorizer(stop_words=stop_words, token_pattern=token_pattern) |
我们在创建的时候,有两个构造参数,可以自定义停用词stop_words和规律规则token_pattern。需要注意的是传递的数据结构,停用词stop_words是一个列表List类型,而过滤规则token_pattern是正则表达式。
什么是停用词?停用词就是在分类中没有用的词,这些词一般词频TF高,但是IDF很低,起不到分类的作用。为了节省空间和计算时间,我们把这些词作为停用词stop words,告诉机器这些词不需要帮我计算。
| 参数表 | 作用 |
|---|---|
| stop_words | 自定义停用词表,为列表list类型 |
| token_pattern | 过滤规则,正则表达式,如r”(?u)\b\w+\b” |
当我们创建好TF-IDF向量类型时,可以用fit_transform帮我们计算,返回给我们文本矩阵,该矩阵表示了每个单词在每个文档中的TF-IDF值。
| 方法表 | 作用 |
|---|---|
| fit_transform(X) | 拟合模型,并返回文本矩阵 |
在我们进行fit_transform拟合模型后,我们可以得到更多的TF-IDF向量属性,比如,我们可以得到词汇的对应关系(字典类型)和向量的IDF值,当然也可以获取设置的停用词stop_words。
| 属性表 | 作用 |
|---|---|
| vocabulary_ | 词汇表;字典型 |
| idf_ | 返回idf值 |
| stop_words_ | 返回停用词表 |
举个例子,假设我们有4个文档:
文档1:this is the bayes document;
文档2:this is the second second document;
文档3:and the third one;
文档4:is this the document。
现在想要计算文档里都有哪些单词,这些单词在不同文档中的TF-IDF值是多少呢?
首先我们创建TfidfVectorizer类:
1 | from sklearn.feature_extraction.text import TfidfVectorizer |
然后我们创建4个文档的列表documents,并让创建好的tfidf_vec对documents进行拟合,得到TF-IDF矩阵:
1 | documents = [ |
输出文档中所有不重复的词:
1 | print('不重复的词:', tfidf_vec.get_feature_names()) |
运行结果
1 | 不重复的词: ['and', 'bayes', 'document', 'is', 'one', 'second', 'the', 'third', 'this'] |
输出每个单词对应的id值:
1 | print('每个单词的ID:', tfidf_vec.vocabulary_) |
运行结果
1 | 每个单词的ID: {'this': 8, 'is': 3, 'the': 6, 'bayes': 1, 'document': 2, 'second': 5, 'and': 0, 'third': 7, 'one': 4} |
输出每个单词在每个文档中的TF-IDF值,向量里的顺序是按照词语的id顺序来的:
1 | print('每个单词的tfidf值:', tfidf_matrix.toarray()) |
运行结果:
1 | 每个单词的tfidf值: [[0. 0.63314609 0.40412895 0.40412895 0. 0. |