【机器学习】TF-IDF以及TfidfVectorizer

2023-09-17 22:24:23

TF-IDF定义

TF-IDF: 全称为"词频一逆文档频率"。
  TF:某一给定词语在该文档中出现的频率。 T F w = 词语 w 在该文档中个数 该文档内总词个数 TF_w = \frac{词语w在该文档中个数}{该文档内总词个数} TFw=该文档内总词个数词语w在该文档中个数
  IDF:整个训练集文档集合一共由 N N N篇文档组成,其中包含某个给定词语 w w w的文档数为 M M M. 则该给定词的 I D F IDF IDF值为: I D F = l o g e ( N M + 1 ) IDF=log_e(\frac{N}{M+1}) IDF=loge(M+1N),M+1是防止分母=0。
  一个词的 T F TF TF值反映了该词在某一篇文档中的重要性,而它的 I D F IDF IDF值则反映了它在整个文档集中的普遍重要程度。二者的乘积(TF-lDF ) 相当于取TF 和IDF的交集, 其值理论上可以较好地反映各个词的分类特征。某一特定文件内的较高词语频次,以及该词语在整个文件集合中的较低频次,可以产生较高的TF-IDF值,TF-IDF算法倾向于过滤常见词语,保留重要词语。经常结合余弦相似度用于向量空间中,判断两份文件的相似度。

python实现

直接使用TfidfVectorizer

这里采用的是[“Chinese Beijing Chinese”, “Chinese Chinese Shanghai”,“Chinese Macao”,“Tokyo Japan Chinese”]这个训练语料库,做一个简单的试验。
起初,我以为这样就能解决:

from sklearn.feature_extraction.text import TfidfVectorizer
tv = TfidfVectorizer()  # 实例化tf实例
train = ["Chinese Beijing Chinese", "Chinese Chinese Shanghai","Chinese Macao","Tokyo Japan Chinese"]  # 输入训练集矩阵,每行表示一个文本
tv_fit = tv.fit_transform(train)  # 训练,构建词汇表以及词项idf值,并将输入文本列表转成VSM矩阵形式
print(f'词汇表{tv.get_feature_names_out()}')  # 查看一下构建的词汇表
print(f'不同词语对应下标:{tv.vocabulary_}')
print(f'矩阵{tv_fit.toarray()}')  # 查看输入文本列表的VSM矩阵

  这是借助TfidfVectorizer进行实现的,结果如下:[‘beijing’ ‘chinese’ ‘japan’ ‘macao’ ‘shanghai’ ‘tokyo’]代表了语料库内所有的词语;{‘chinese’: 1, ‘beijing’: 0, ‘shanghai’: 4, ‘macao’: 3, ‘tokyo’: 5, ‘japan’: 2}是不同词语对应下标,这个在下面的矩阵里面代表这个词语在第几列;
  矩阵的每一行代表一个文档内的每一个词语的TF-IDF值。举个例子,对于文档"Chinese Beijing Chinese"来讲它的结果就是第0行[0.69183461,0.722056 ,0. , 0. , 0. , 0. ],该文档中只有Chinese和Beijing 这两个词语,因此只有两个元素非零,其中chinese对应列是1,于是它在该文档中的TF-IDF值为0.722056,beijing1对应列是0.于是它在该文档中的TF-IDF值为0.69183461。
在这里插入图片描述

结果解释

  但是仔细一看,欸???为什么?这些数值是什么意思???
  就拿"Chinese Beijing Chinese"里的chinese来说,根据定义, T F = 2 3 , I D F = l o g e ( 4 5 ) , T F − I D F = − 0.1487 ? ? ? TF = \frac{2}{3},IDF = log_e(\frac{4}{5}),TF-IDF = -0.1487??? TF=32IDF=loge(54),TFIDF=0.1487???,不对劲啊!!
我就在网上找啊,发现TF_IDF公式还挺多,不止有定义里的;
一个例子来使用sklearn中的TfidfVectorizer
tf-idf原理 & TfidfVectorizer参数详解及实战
经过我实践证明TfidfVectorizer使用的计算TF-IDF公式如下:
T F = 给定词语在该文档中出现的频数 I D F = l n ( 1 + N 1 + M ) + 1 T F I D F = T F ∗ I D F 整个训练集文档集合一共由 N 篇文档组成,其中包含某个给定词语的文档数为 M . TF = 给定词语在该文档中出现的频数\\ IDF = ln(\frac{1+N}{1+M})+1\\ TFIDF = TF*IDF\\ 整个训练集文档集合一共由N篇文档组成,其中包含某个给定词语的文档数为M. TF=给定词语在该文档中出现的频数IDF=ln(1+M1+N)+1TFIDF=TFIDF整个训练集文档集合一共由N篇文档组成,其中包含某个给定词语的文档数为M.
然后TfidfVectorizer还对每个文档的向量进行规范化,即对于每个文档的词语TF-IDF向量 v v v还要除以2范数, v ∣ ∣ v ∣ ∣ 2 \frac{v}{||v||_2} ∣∣v2v

手敲代码

这是我根据这个公式写出的python代码:

# 求逆文档频率IDF
def Idf(nd,df):
    return np.log((1+nd)/(1+df)) + 1

train = ["Chinese Beijing Chinese", "Chinese Chinese Shanghai","Chinese Macao","Tokyo Japan Chinese"] 
wordInDoc = []  # 记录在每个文档语句中单词出现次数,元素为字典,每个字典记录该文档中单词出现次数
wordInCor = {}  # 语料库中单词出现的文档
'''
不会重复
'''
# 求出每个文档语句中单词出现次数
for doc in train:
    words = doc.split()  # 将句子按空格分割成单词
    word_counts = {}  # 使用字典存储词语出现次数
    for word in words:
        word = word.strip('.,!?"()[]{}')  # 去除标点符号
        word = word.lower()  # 转换为小写以忽略大小写差异
        # 更新字典中词语的出现次数
        word_counts[word] = word_counts.get(word,0)+1
    wordInDoc.append(word_counts)  # 添加该文档字典
    
# 语料库中单词出现的文档
for i  in wordInDoc:  # 遍历每个文档字典
    for j in i:  # 如果词汇j出现在文档i中则该词汇出现次数+1
        wordInCor[j] = wordInCor.get(j,0)+1
        
# 给出每个词汇在哪一列
ind = {}  # 每个词汇对应下标,对应后面,词汇result中的哪一列
for i,word in enumerate(list(np.sort(list(wordInCor.keys())))):
    ind[word] = i
    
# 结果是一个稀疏矩阵
result = np.zeros((len(train),len(wordInCor.keys())))
for i in  range(len(train)):  # 遍历每个文档
    for word in ind.keys():  # 遍历每个词汇
        if word in wordInDoc[i].keys():  # 如果该词汇在该文档中,则计算
            tf = wordInDoc[i][word]  # wordInDoc[i]第几个文档的字典,wordInDoc[i][word]该文档中词汇出现次数?
                                    # 这边其实是有点疑问的,网上tf公式大多是频率,但是TfidfVectorizer从结果来倒推,TfidfVectorizer用的是频数
            idf = Idf(len(train),wordInCor[word])  # len(train)为文档总数=4,wordInCor[word]为该词汇在文档中出现次数
            tfidf = tf*idf
            result[i,ind[word]] = tfidf
# 规范标准化,除以2范数
result = result/np.sqrt((result**2).sum(axis = 1)).reshape(-1,1)
print(result)

结果:可以看出结果是和调用TfidfVectorizer是一样的。当然,这里词语对应的列与上面不同。
在这里插入图片描述

总结

  TfidfVectorizer使用的计算TF-IDF的公式与定义有差别。但实际上表达的意思是相同的,都是在该文档中的重要性TF乘以在语料库中的重要性IDF的乘积。
  np.log()其实是以e为底的,所以如果要计算以其他数为底的对数,需要进行换底公式 L o g a b = l o g c b l o g c a Log_ {a}b=\frac {log_ {c}b} {log_ {c}a} Logab=logcalogcb

def Log(newd,number): #newd新底
	return np.log(number)/np.log(newd)
Log(10,10)
更多推荐

优漫动游设计心得

4、团队激励优漫动游大型互联网公司一般都有一套严格的加薪制度,所以别总指望通过加薪来提升士气。那么日常团队鼓励就非常重要了。09年麦肯锡就最激励员工的因素进行的一项调查显示,排在前两位的分别是“直接领导的公开赞扬”和“领导的注意”。此外,在赞扬方面,公开赞扬也比私下赞扬对员工的正面影响要放大许多倍。因为这时你创造的不仅

C语言系统化精讲(一):C 语言开发环境搭建

文章目录一、Windows开发环境搭建1.1安装mingw编译器1.2下载并安装CLion1.3启动CLion二、Linux开发环境搭建(建议使用)2.1VMwareWorkstationPro软件简介及安装2.2安装Ubuntu系统2.2.1Ubuntu下载2.2.2安装Ubuntu2.2.3安装共享文件夹2.3概念

使用NRM管理Node镜像源,提升包下载速度

前言在日常开发中,我们经常会使用到Node.js来构建和运行JavaScript应用程序。然而,在使用Node.js时,由于网络环境的限制,我们可能会遇到包下载速度缓慢的问题。为了解决这个问题,本文将介绍如何使用NRM(NodeRegistryManager)来管理Node镜像源,从而提升包下载速度。什么是NRM?NR

JavaScript前端跨页面通信:实现页面间的数据传递与交互

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录引言1.前端跨页面通信的概述2.前端跨页面通信的属性2.1双向通信2.2异步通信2.3安全性2.4可靠性3.前端跨页面通信的应用场景3.1多标签页间的数据共享3.2页面间的消息通知和事件触发3.3页面间的数据传

如何在Python爬虫程序中使用HTTP代理?

在进行网络爬虫时,我们经常需要使用代理服务器来隐藏自己的真实IP地址,以避免被目标网站封禁或限制访问。本文将介绍如何将HTTP代理配置到Python爬虫程序中使用。什么是HTTP代理?HTTP代理是一种网络代理,它充当客户端和服务器之间的中介,接收客户端请求并将其转发给服务器。代理服务器可以隐藏客户端的真实IP地址,使

day19正则表达式

今日内容正则表达式教学目标能够理解正则表达式的作用能够使用正则表达式的字符类能够使用正则表达式的逻辑运算符能够使用正则表达式的预定义字符类能够使用正则表达式的限定符能够使用正则表达式的分组能够在String的split方法中使用正则表达式正则表达式1.1正则表达式的概念及演示在Java中,我们经常需要验证一些字符串,例

【Flutter】2023 Google 开发者大会给 Fluter 带来了什么

文章目录一、2023年谷歌开发者大会概览二、Flutter年度进展三、Dart年度进展四、Material3年度进展五、推荐使用Flutter跨平台开发六、参考资料一、2023年谷歌开发者大会概览你知道吗,今年的谷歌开发者大会真是令人期待。从5月10日的线上GoogleI/O大会开始,到9月6日至7日在上海世博中心的现

2023年华为杯研究生数学建模竞赛辅导

2023年华为杯研究生数学建模竞赛辅导各研究生培养单位:中国研究生数学建模竞赛作为教育部学位管理与研究生教育司指导,中国学位与研究生教育学会、中国科协青少年科技中心主办的“中国研究生创新实践系列大赛”主题赛事之一,是一项面向在校研究生进行数学建模应用研究与实践的学术竞赛活动,是广大在校研究生提高建立数学模型和运用互联网

Linux多线程【线程控制】

✨个人主页:北海🎉所属专栏:Linux学习之旅🎃操作环境:CentOS7.6阿里云远程服务器文章目录🌇前言🏙️正文1、线程知识补充1.2、线程私有资源1.3、线程共享资源1.4、原生线程库2、线程控制接口2.1、线程创建2.1.1、一批线程2.2、线程等待2.3、线程终止2.4、线程实战2.5、其他接口2.5.

Flutter动态化开发之Fair实战

一、背景目前移动端应用的版本更新,最常见的方式是定期发版,无论是安卓还是iOS,都需要提交新的安装包到应用市场进行审核。审核通过后,用户在应用市场进行App的下载更新。而动态化,就是不依赖更新程序安装包,就能动态实时更新页面的技术。相比动态化技术,定期发版更新应用的方式存在一些问题,比如:审核周期长,且可能审核不通过。

【完全二叉树魔法:顺序结构实现堆的奇象】

本章重点二叉树的顺序结构堆的概念及结构堆的实现堆的调整算法堆的创建堆排序TOP-K问题1.二叉树的顺序结构普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是

热文推荐