白话 贝叶斯公式_关于tfidf及多项式/伯努利贝叶斯用于文本分类的详细讲解(完整示例代码+手工推导)...

本文详细介绍了如何计算TF-IDF,并探讨了如何使用多项式和伯努利贝叶斯分类器进行文本分类。文中解释了为什么TF-IDF可以与这两种贝叶斯模型结合,以及它们之间的区别,同时通过实例展示了它们在实际应用中的效果。
摘要由CSDN通过智能技术生成

关于tfidf以及文本分类中贝叶斯模型的介绍,网络上有很多。然而,大部分文章存在着讲解片面的情况,且忽视了几个非常容易产生误解的地方。例如,tfidf的取值一般不是非负整数,其对应的文档向量并不满足多项分布,那为什么许多人将tfidf特征表示作为多项式贝叶斯分类器

的输入?在这篇文章中,我将结合简单的示例代码,非常详细地讲解以下几个问题。读完这篇文章,相信你会对tfidf以及基于多项式/伯努利贝叶斯的文本分类有一个深入的理解。

一、如何计算tf-idf?

二、如何将多项式/伯努利贝叶斯分类器用于文本分类?二者有什么区别?

三、为什么tfidf后可以直接接多项式/伯努利贝叶斯用于文本分类

一、如何计算tf-idf?

这里我用了一个简单的例子,分别通过sklearn以及手工方式计算了tfidf值,目的是更清晰地展示出计算的过程。

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = ["good nice nice",
         "good great great great",
         "nice nice great",
         "bad bad sad mad",
         "sad sad sad bad mad mad"]
tfidf_vect = TfidfVectorizer(use_idf=True, smooth_idf=True, norm=None)
tfidf_features = tfidf_vect.fit_transform(corpus)
print(tfidf_vect.get_feature_names())
“”“
打印出来的结果如下:
['bad', 'good', 'great', 'mad', 'nice', 'sad']
“”“
print(tfidf_features.toarray())
“”“
打印出来的结果如下,每一行对应一篇文档,
每一列对应['bad', 'good', 'great', 'mad', 'nice', 'sad']中的一个单词的tfidf值:
[[0.         1.69314718 0.         0.         3.38629436 0.        ]
 [0.         1.69314718 5.07944154 0.         0.         0.        ]
 [0.         0.         1.69314718 0.         3.38629436 0.        ]
 [3.38629436 0.         0.         1.69314718 0.         1.69314718]
 [1.69314718 0.         0.         3.38629436 0.         5.07944154]]
“”“
“”“
我们来手动计算一下tfidf是否与代码的计算结果一致。
首先是计算公式:

tf(x) = x在某文档中出现的次数
idf(x) = 1 + ln((1+文档总数)/(1+出现了x的文档总数))
tfidf(x) = tf(x) * idf(x)

以上公式有两点需要注意的地方:(1)sklearn使用e为对数log的底。(2)这里的idf采用了平滑版本。

接下来我们来计算第一篇文档中单词good与nice的tfidf值:

tf(good) = 1  [good在文档一中出现了1次]
idf(good) = 1 + ln((1+5)/(1+2)) = 1 + ln2  【文档总数:5;出现了good的文档总数:2】
tf-idf(good) = tf(good) * idf(good) = 1.69314718
  
tf(nice) = 2  [nice在文档一中出现了2次]
idf(nice) = 1 + ln((1+5)/(1+2)) = 1 + ln1.5 【文档总数:5;出现了nice的文档总数:2】
tf-idf(nice) = tf(nice) * idf(nice) = 3.38629436

可以看出结果是一致的。
“”“

二、如何将多项式/伯努利贝叶斯分类器用于文本分类?二者有什么区别?

接着上面的例子,首先给出代码(注意这段代码要接着上一小节中的代码运行,下同)。注意为了方便理解,这里我用的是词袋模型(bag-of-words)。下一节中我们将探讨,tfidf如何作用于多项式/伯努利贝叶斯分类器?

from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.feature_extraction.text import CountVectorizer

doc = ['great nice nice']

bow_vect = CountVectorizer()
bow_features = bow_vect.fit_transform(corpus)
bow_doc = bow_vect.transform(doc)
print(bow_doc)
"""
得到bow(词袋模型)表示的文档,输出如下:
  (0, 2)	1
  (0, 4)	2
"""
clf1 = MultinomialNB()
clf1.fit(bow_features, [1, 1, 1, 0, 0])
print(clf1.predict_proba(bow_doc))
"""
参数[1, 1, 1, 0, 0]对应corpus中五篇文档的标签。
MultinomialNB(多项式贝叶斯)预测概率输出如下:
[[0.00530504 0.99469496]]
"""
"""
我们来讲解一下MultinomialNB(多项式贝叶斯)的原理。
首先介绍基本的贝叶斯公式P(c|doc)= P(c)* P(doc|c)/ P(doc),其中P(doc)由于在P(c=1|doc)与P(c=0|doc)中都会出现,可以不考虑。
再介绍MultinomialNB的计算公式:
P(c)= 类别c下的单词总数/所有类别下的单词总数
P(word|c)= 单词word在类c中出现的次数/类别c下的单词总数
平滑系数取1的平滑版本:P(word|c)= (单词word在类c中出现的次数+1)/(类别c下的单词总数+V),V是词汇表大小,注意重复单词在V中只算1个
使用MultinomialNB平滑版本的公式,我们对测试文档doc进行预测:
P(c = 1|doc = ['great nice nice'])= P(1)* P(doc = ['great nice nice']|1)= P(1)* P(great|1)* P(nice|1)* P(nice|1)
P(c = 0|doc = ['great nice nice'])= P(0)* P(doc = ['great nice nice']|0)= P(0)* P(great|0)* P(nice|0)* P(nice|0)
类别1下的单词总数是10,类别0下的单词总数是10,所有类别下的单词总数是20,因此P(1)= 10 / 20, P(2)= 10 / 20
单词great在类别1中出现的次数是4,类别1下的单词总数是10,词汇表V大小是6,因此P(great|1)= (4+1)/(10+6)
其余计算同理,不再赘述。
需要注意的是,这里计算出的预测概率是没有归一化的,而sklearn给出的是归一化后的结果。
"""
clf2 = BernoulliNB()
clf2.fit(bow_features, [1, 1, 1, 0, 0])
print(clf2.predict_proba(bow_doc))
"""
BernoulliNB(伯努利贝叶斯)预测概率输出如下:
[[0.00657917 0.99342083]]
"""
"""
我们来讲解一下BernoulliNB(伯努利贝叶斯)的原理。BernoulliNB的计算公式:
P(c)= 类别c下的文档总数/所有类别下的文档总数
P(word|c)= 包含单词word的文档在类别c中出现的次数/类别c下的文档总数
平滑系数取1的平滑版本:P(word|c)= (包含单词word的文档在类别c中出现的次数+1)/(类别c下的文档总数+C),C是类别数目。
使用BernoulliNB平滑版本的公式,我们对测试文档doc进行预测:
P(c = 1|doc = ['great nice nice'])= P(1)* P(doc = ['great nice nice']|1)= P(1)* P(great|1)* P(nice|1)* P(nice|1)
P(c = 0|doc = ['great nice nice'])= P(0)* P(doc = ['great nice nice']|0)= P(0)* P(great|0)* P(nice|0)* P(nice|0)
类别1下的文档总数是3,类别0下的文档总数是2,所有类别下的文档总数是5,因此P(1)= 3/5,P(0)= 2/5
包含单词great的文档在类别1中出现的次数是2,类别c下的文档总数是3,类别数目C包括1/0两个类别所以是2,因此P(great|1)=(2+1)/(3+2)
其余计算同理,不再赘述。
同样,这里计算出的预测概率是没有归一化的,而sklearn给出的是归一化后的结果。
"""

以上就是多项式/伯努利贝叶斯分类器用于文本分类的内容。本质上,在多项分布中,有n个事件(单词),每个事件的发生次数(单词数量)是随机变量;在二项分布中,有两个事件(包含单词与不包含单词),每个事件的发生次数(包含/不包含单词的文档数量)是随机变量。用一句大白话总结,多项式贝叶斯统计的是单词,伯努利贝叶斯统计的是出现了单词的文档,一个是单词级别的贝叶斯模型,一个是文档级别的贝叶斯模型。

三、为什么tfidf后可以直接接多项式/伯努利贝叶斯用于文本分类

不知道大家有没有好奇过,为什么网上很多关于文本分类的教程里,tf-idf直接就接上了多项式贝叶斯(MultinomialNB)?根据多项式贝叶斯的定义,其输入应该是服从多项分布的随机向量X=

,其中
表示事件i发生的次数,
是非负整数!但tf-idf值是分数!此刻的输入明明 不满足多项分布,又为什么能用多项式贝叶斯呢?

我开始注意到这一点的时候,也是一头雾水。因此,我特地梳理了一下文本分类任务中朴素贝叶斯的用法,希望能给困惑中的朋友一点帮助。

我们从以下几个角度讨论这个问题:

(1)tf-idf与朴素贝叶斯有什么关系?

(2)tf-idf用于多项式贝叶斯(MultinomialNB)时,发生了什么?

(3)tf-idf用于伯努利贝叶斯(BernoulliNB)时,发生了什么?

首先回答(1),tf-idf与朴素贝叶斯有什么关系?

抛出观点:tf-idf与朴素贝叶斯没有任何关系!!

因为贝叶斯分类器本质上是数数!它只在乎这个特征/单词出现了多少次(多项式贝叶斯)或有没有出现(伯努利贝叶斯),而不在乎特征值是不是什么tf-idf。

那为什么网上的代码中,铺天盖地地在tf-idf后接多项式贝叶斯呢?它们错了吗?

要回答这个问题,我们来回答问题(2):tf-idf用于多项式贝叶斯(MultinomialNB)时,发生了什么?

sklearn关于问题(2),有一段官方解释如下,【地址】:

The multinomial Naive Bayes classifier is suitable for classification with discrete features (e.g., word counts for text classification). The multinomial distribution normally requires integer feature counts. However, in practice, fractional counts such as tf-idf may also work.

也就是说,sklearn在实现中,是认为tf-idf可以作用于多项式贝叶斯的。但是具体的实现方式似乎也没有说得很清楚?

于是我又查阅了很多网络上的资料,在stackoverflow上找到了一段解释【地址】:

The (traditional) Multinomial N.B. model considers a document D as a vocabulary-sized feature vector x, where each element xi is the count of term i i document D. By definition, this vector x then follows a multinomial distribution, leading to the characteristic classification function of MNB.
When using TF-IDF weights instead of term counts, our feature vectors are (most likely) not following a multinomial distribution anymore, so the classification function is not theoretically well-founded anymore. However, it does turn out that tf-idf weights instead of counts work (much) better.
How would TFIDF values even work with this formula?
In the exact same way, except that the feature vector x is now a vector of tf-idf weights and not counts.

总结一下,就是说,使用tf-idf特征时,文档向量确实是不符合多项分布的。但是,我们可以假装其符合多项分布,照常使用多项式贝叶斯的公式来进行文本分类。唯一要注意的地方是,我们将分数形式的tf-idf权重看作单词在某文档中出现的次数。

而这样做的理由是,实践表明,使用tf-idf+多项式贝叶斯的结果,要比bow+多项式贝叶斯更好。

我们来看一段代码,分别使用tf-idf与bow训练多项式贝叶斯。(继续接着上一段代码运行的,下同)

clf1 = MultinomialNB()
clf1.fit(tfidf_features, [1, 1, 1, 0, 0])
tfidf_doc = tfidf_vect.transform(doc)
print(clf1.predict_proba(tfidf_doc))
"""
输出tf-idf权重下MultinomialNB的预测概率:
[[1.99675011e-05 9.99980032e-01]]
"""
clf2 = MultinomialNB()
clf2.fit(bow_features, [1, 1, 1, 0, 0])
print(clf2.predict_proba(bow_doc))
"""
输出bag-of-words权重下MultinomialNB的预测概率:
[[0.00530504 0.99469496]]
"""

可以看出,预测结果是不同的。

最后是问题(3):tf-idf用于伯努利贝叶斯(BernoulliNB)时,发生了什么?

直接上代码(继续接着上一段代码运行的)。

clf1 = BernoulliNB()
clf1.fit(tfidf_features, [1, 1, 1, 0, 0])
tfidf_doc = tfidf_vect.transform(doc)
print(clf1.predict_proba(tfidf_doc))
"""
输出tf-idf权重下BernoulliNB的预测概率:
[[0.00657917 0.99342083]]
"""
clf2 = BernoulliNB()
clf2.fit(bow_features, [1, 1, 1, 0, 0])
print(clf2.predict_proba(bow_doc))
"""
输出bag-of-words权重下BernoulliNB的预测概率:
[[0.00657917 0.99342083]]
"""

可以看出,预测结果相同伯努利贝叶斯不在乎输入的是tf-idf特征还是bow特征,因为它考虑的仅仅是这个特征/单词是否存在,而不在乎它的权重是多少!

至此,关于tfidf及多项式/伯努利贝叶斯用于文本分类的介绍完毕。

如有疏漏,欢迎指正~

好的,我们可以使用TensorFlow来实现文本分类。首先需要下载数据集并安装TensorFlow。 1. 下载数据集 我们可以使用以下命令从GitHub上下载`waimai_10k.csv`数据集: ``` !wget https://raw.githubusercontent.com/SophonPlus/ChineseNlpCorpus/master/datasets/waimai_10k/waimai_10k.csv ``` 2. 安装TensorFlow 我们可以使用以下命令安装TensorFlow: ``` !pip install tensorflow ``` 3. 加载数据集 我们可以使用Pandas库来加载数据集: ```python import pandas as pd df = pd.read_csv('waimai_10k.csv') ``` 4. 数据预处理 在进行文本分类之前,我们需要对数据进行预处理。首先,我们将标签转换为数字,然后将数据集拆分为训练集和测试集。 ```python from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split # 将标签转换为数字 le = LabelEncoder() df['label'] = le.fit_transform(df['label']) # 拆分数据集为训练集和测试集 train_df, test_df = train_test_split(df, test_size=0.2, stratify=df['label'], random_state=42) ``` 5. 特征工程 我们需要将文本数据转换为计算机可以理解的形式。在这里,我们可以使用词袋模型,并使用TF-IDF进行特征缩放。 ```python from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer # 使用词袋模型 count_vect = CountVectorizer() X_train_counts = count_vect.fit_transform(train_df['review']) X_test_counts = count_vect.transform(test_df['review']) # 使用TF-IDF进行特征缩放 tfidf_transformer = TfidfTransformer() X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts) X_test_tfidf = tfidf_transformer.transform(X_test_counts) ``` 6. 训练模型 我们可以使用TensorFlow的Keras API来训练模型。在这里,我们将使用一个简单的神经网络模型。 ```python from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout # 定义神经网络模型 model = Sequential() model.add(Dense(64, input_dim=X_train_tfidf.shape[1], activation='relu')) model.add(Dropout(0.5)) model.add(Dense(32, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(1, activation='sigmoid')) # 编译模型 model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # 训练模型 model.fit(X_train_tfidf, train_df['label'], epochs=10, batch_size=32, validation_split=0.2) ``` 7. 评估模型 最后,我们可以使用测试集来评估模型的性能。 ```python # 在测试集上评估模型 score = model.evaluate(X_test_tfidf, test_df['label'], batch_size=32) print('Test loss:', score[0]) print('Test accuracy:', score[1]) ``` 完成以上步骤后,我们就可以使用TensorFlow对文本进行分类了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值