NLP--词频统计和TF-IDF总结【实践】

6 篇文章 0 订阅
4 篇文章 3 订阅

前言

最一开始,在学习《Python人工智能:原理、实践及应用》中涉及到了写词频统计,只是对词频进行了统计。但在我们在日常工作中,涉及词频统计,我们往往绕不开TF-IDF,因此对词频-逆文档频率进行了学习总结,以及日常中你经常会被问到的几个问题。

  1. 为什么TF要进行标准化操作?
  2. 为什么要取对数?
  3. 为什么IDF分母中要进行+1(IDF如何进行平滑处理的)?
  4. 为什么要词频 * 逆文档频率(TF-IDF要用乘法)?

词频统计原理

词频统计是指输入一些字符串(手动输入或者从指定的文件读取),用程序来统计这些字符串中总共有多少个单词,每个单词出现的次数。单词的总数(即为Total)为不重复的单词数总和。

词频指词的频率,即词在一定的语料中出现的次数。

代码实现

# Hamlet文档可在https://python123.io/resources/pye/hamlet.txt下载
with open('hamlet.txt', 'r', encoding='utf-8') as fr:
    text = fr.read().lower()
    # text = text.replace(',', ' ').replace('.', ' ').replace('!', ' ').replace('?', ' ')\
    #     .replace(';', ' ').replace(':', ' ')
    # 去除标点符号
    for char in "!'#$%&()*+,-./:;<=>?@[\\\\]^_{|}~":
        text = text.replace(char, ' ')

text = text.split()
counts = {}
# 词频统计
for i in text:
    counts[i] = counts.get(i, 0) + 1

items = list(counts.items())
# 高频词展示
for i in sorted(items, key=lambda x: x[1], reverse=True)[:10]:
    print('{:<6} -> {}'.format(i[0], i[1]))

TF-IDF

TF-IDF(Term Frequency–Inverse Document Frequency)是一种用于信息检索与文本挖掘的常用加权技术。

TF-IDF 是一种统计方法,用以评估一字词对于一个文档集或一个语料库中的其中一份文档的重要程度。字词的重要性随着它在文档中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。简单的解释为,一个单词在一个文档中出现次数很多,同时在其他文档中出现此时较少,那么我们认为这个单词对该文档是非常重要的。

TF

TF(Term Frequency,词频),某个词条在文中出现的次数。

词频( T F ) = 某个词在文档中的出现次数 词频(TF)=某个词在文档中的出现次数 词频(TF=某个词在文档中的出现次数

TF标准化

词频( T F ) = 某个词在文档中出现的次数 / 文档的总词数 词频(TF)=某个词在文档中出现的次数/文档的总词数 词频(TF=某个词在文档中出现的次数/文档的总词数

IDF

IDF(Inverse Document Frequency,逆向文档频率)

逆文档频率( I D F ) = l o g ( 语料库的文档总数 / ( 包含该词的文档数 + 1 ) ) 逆文档频率(IDF)=log(语料库的文档总数/(包含该词的文档数+1)) 逆文档频率(IDF=log(语料库的文档总数/(包含该词的文档数+1))

如果只用词频来表达一个词对一篇文档的重要程度显然是不合适的,因为在一篇文档里面,可能出现频率很高的词是一些没有意义的词语,真正能代表这篇文档的关键词可能只出很少的次数。(如果有太多文档都涵盖了某个单词,这个单词也就越不重要,或者说是这个单词就越没有信息量)因此,我们需要对 TF 的值进行修正,而 IDF 的想法是用 DF (文档频率)的倒数来进行修正。倒数的应用正好表达了这样的思想,DF 值越大越不重要。

为什么TF要进行标准化操作?

  • 解决长文档、短文档问题,仅用频次来表示,长文本中出现频次高的概率会更大,这一点会影响到不同文档词权值的比较。(文档有长短之分,为了便于不同文档的比较)

为什么要取对数?

  • 使用log可以防止权重爆炸。如果某些词只出现一篇或者少数几篇文档中(比如错别字),在没有log的情况下,IDF就会非常小(分母过小),从而影响其权重,而使用log能减轻这种影响。(平滑

  • 文档中的停用词(如“的”,“地”,“了”)词频很高,文档集中含停用词的数量约等于总的文档集数量,即 N / n ≃ N/n \simeq N/n 1( N / n N/n N/n恒大于1)。在只使用TF的情况下,停用词所占的权重很大,但是它并没有区分能力,与我们的期望不符。使用IDF之后,由于log(1)=0,则停用词通过TF-IDF计算出的权重就为0(根号达不到这样的效果),就可以消除很多停用词的影响。

  • 利用对数来达到非线性增长的目的,压缩了数据之间的距离,使数据更加平稳,削弱他们之间的差异性。缩小数据的绝对数值,方便计算(缩放

为什么IDF分母中要进行+1(IDF如何进行平滑处理的)?

  • 采用了拉普拉斯平滑(分母+ 1)是为了避免分母为 0(即所有文档都不包含该词),增强了算法的健壮性。如果一个词越常见那么分母就越大,逆文档频率就越小越接近 0。

为什么要词频 * 逆文档频率(TF-IDF要用乘法)?

  • TF * IDF的乘积可以提高重要性较高的词的权重,同时降低重要性较低的词的权重,从而更好地区分不同的词语。

    文档中的停用词(如“的”,“地”,“了”)词频很高,文档集中含停用词的数量约等于总的文档集数量,即 N / n ≃ N/n \simeq N/n 1( N / n N/n N/n恒大于1)。在只使用TF的情况下,停用词所占的权重很大,但是它并没有区分能力,与我们的期望不符。使用IDF之后,由于log(1)=0,则停用词通过TF-IDF计算出的权重就为0(根号达不到这样的效果),就可以消除很多停用词的影响。

  • 涉及概率,用乘法,简单有效。

TF-IDF优缺点:

  • 优点:易于计算

  • 缺点:

    • 不能捕捉词在文档中的位置,无法获取语义。
    • TF-IDF 算法主要适用于英文,中文首先要分词,分词后要解决多词一义,以及一词多义问题,这两个问题通过简单的TF-IDF方法不能很好的解决。
    • 对文档中出现次数较少的重要人名、地名的提取效果不佳

代码实现

import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer,TfidfTransformer

# 停用词表可在我的资源中免费下载
stop_words = './停用词/en_stopwords.txt'
with open(stop_words, 'r', encoding='utf-8') as fr:
    stopwords_list = "".join(fr.readlines()).split()
with open('hamlet.txt', 'r', encoding='utf-8') as fr:
    text = fr.read().lower()

    for char in "!'#$%&()*+,-./:;<=>?@[\\\\]^_{|}~":
        text = text.replace(char, ' ')

# 去除停用词,避免停用词对整个文档词的影响
text = [word for word in text.split() if word not in stopwords_list]

# TfidfVectorizer=TfidfTransformer + CountVectorizer
# fit_transform方法将语料转化成TF-IDF权重矩阵
tfidf_vec = TfidfVectorizer()
tfidf_matrix = tfidf_vec.fit_transform(text)
# 得到语料库所有不重复的词
print(tfidf_vec.get_feature_names())
# 得到每个单词对应的id值
print(tfidf_vec.vocabulary_)
# 得到每个句子所对应的向量,向量里数字的顺序是按照词语的id顺序来的
print(tfidf_matrix.toarray())
# print(tfidf_matrix.todense())
"""
m行n列处值的含义是词汇表中第n个词在第m篇文档的TF-IDF值。提取单篇文档的关键词只需要将矩阵按行的值从大到小排序取前几个即可。如果要提取所有文档的关键词,我们可以将矩阵按列求和,得到每个词汇综合TF-IDF值。
"""
vec_array = tfidf_matrix.toarray().sum(axis=0).tolist()
df = pd.DataFrame(vec_array, index=tfidf_vec.get_feature_names(), columns=['tf-idf'])
# 如果只看TF-IDF分数值,可以直接输出df数据
# 如果进行关键词提取,可按照TF-IDF分数值排序后,取出TOP-N个即可
key_word = df.sort_values(by=['tf-idf'], ascending=False).head()
print(key_word)

总结

以上是我个人在学习过程中的记录所学,希望对正在一起学习的小伙伴有所帮助!!!
如果对你有帮助,希望你能一键三连【关注、点赞、收藏】!!!

参考链接

https://blog.csdn.net/qq_52181283/article/details/125013666

https://www.cnblogs.com/chenying99/p/4596707.html

https://52opencourse.com/187/idf%E9%80%86%E6%96%87%E6%A1%A3%E9%A2%91%E7%8E%87%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8log

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

故事挺秃然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值