# 改进TF-IDF算法

之前做特色词或者类目词挖掘的时候多多少少是用了tfidf思想的，因此打算总结一下这种方案。

### 1.传统tf-idf

传统tfidf是在BoW模型下对词特征进行加权的，加权了之后主要有两个作用：

* 根据特征词的tfidf大小筛选代表文档的关键词
* 得到tfidf加权的one-hot向量作为文档的表示

第二个作用作为文档表示，主要是在embedding大量应用之前的文档特征表示，也算是高维sparse的文本embedding，经常可以后跟传统机器学习算法(LR,SVM等)作文本分类的输入特征。 目前文本分类基本是深度学习的天下了，不过在一些标注数据缺乏的无监督任务上，tfidf还是有其自身的价值的。而这里面最常用的就是文档关键词提取了。

这里的思想主要是对于文档j的词i，计算其tfidf值: $$tfidf\_{i,j}=tf\_{i,j}log(idf\_i)$$。而 $$tf\_{i,j}$$ 计算为：

![](https://3676603176-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ln2Cwa30IhAwp_pKAP9%2F-Ln5nB5C7iMXUqYaYDH2%2F-Ln5ng1512P279o5Rj-h%2Fimage.png?alt=media\&token=732ab4c8-1c36-46e9-8539-9e9b7f93c095)

$$log(idf\_i)$$ 计算为：

![](https://3676603176-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ln2Cwa30IhAwp_pKAP9%2F-Ln5nB5C7iMXUqYaYDH2%2F-Ln5nkiLz3MRgZGfCFrI%2Fimage.png?alt=media\&token=99652bd6-b6a3-4483-bdbc-be67646e2c72)

这里面的思想很简单，tf描述词i在文档j中的比例，这个比例越大肯定说明词i对于文档j就越重要。但是这样看，肯定是诸如“的，啊”等无意义的常见词出现最多了，因此又引入了idf，逆向文档频率来减轻常用词的权重，也就是说在整个文档集合越常见，他就越不重要。

### 2.传统tf-idf缺点

tf-idf的定义很直观，tf值和idf值直接相乘看上去很合理，单篇文档出现越多这个词就越重要，在所有文档里出现的越少说明越重要。但是直接相乘多少有点拍脑袋的成分，我能不能对tf也求log再乘呢，当然可以，我实际用的时候有时发现效果还更好点。但是这些都可以看作是超参，只能靠试和感觉，这就导致传统的tf-idf有很多缺点：

* 词的位置信息考虑不到，汉语中重要的词通常容易出现在开始和结尾
* 很少见的偏僻词容易被赋予过大的idf权重
* idf在文档集合中进行计算，但是文档集合的内部存在不同类分布不均衡的情况。比如100篇美食文章和1000篇口红的文章组成文档集合，按照传统idf的定义，“菜”的idf会比“口红”大，因为美食文章要少很多。但是实际上它的重要程度并不比“口红”大，只是这里包含“口红”的文章太多了
* 文档中出现次数较少的重要人名、地名等实体信息，由于对应tf太小提取效果不佳

第一点比较好解决，再计算tf的时候按照词出现的位置拍权重就好了。 第二点如果是单一的文章提取关键词比较麻烦，通常是对idf设置一定的阈值，对于特别大的idf就当作是错误词处理。如果是按照文章集合进行提取关键词就能够缓解这种出现过少的词的影响，因此在一两篇内容中偶尔有出现的词不大会在一类内容中都有，如果真的有的话那它的确是该被提取出来的词。 第四点要处理的话得做实体识别，然后再对实体加权。 第三点是主要要改进的地方，可以看出老的方案无法衡量同样的词在不同类下的重要性，具体改进在下文说。

### 3.tf-idf的改进

先看一个例子： &#x20;

![](https://3676603176-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ln2Cwa30IhAwp_pKAP9%2F-Ln5nB5C7iMXUqYaYDH2%2F-Ln5npfMnRjz9r0cGUk0%2Fimage.png?alt=media\&token=e8fecc7e-ed2d-43c0-9d35-578bede5b40e)

c1和c2两个类，分别有14篇和6篇内容，然后包含词m1的文章有9篇属于c1类，1篇属于c2类，包含词m2的文章有5篇属于c1类，5篇属于c2类。

按照传统idf的定义，m1和m2的idf均为IDF1=IDF2=log(20/10+0.01)。但是显然m1应该更值得被关注一点，因为它显著更多出现在c1类中。

因此我们改进的主要思路在于看一个词在某个类中出现的比例是否比在其他类中出现的比例更高，如果是的话，这样的词显然更应该被关注。

基于此得到两种方案：&#x20;

**方案一：**&#x20;

IDF=log(本类含特征词文档数m总文档数N/所有含特征词文档数n+0.01) 可以看出N对于所有词是一样的，一个词在本类出现的越多，在其他类出现的越少，说明这个词对于区分类目越重要。 **方案二***：*

用 $$P\_i$$ 表示特征词i在当前类别中的频率， $$P\_i’$$表示特征词i在其他类别中的频率，对idf的计算为 $$idf=log(1+\frac{p\_i}{p\_i'})$$ . 看出来也是用在当前类出现的频率与其他类中出现的频率的比值来衡量一个词的重要性 这两种方案并没有大的区别，用起来个人感觉差不多。

### 4.改进tf-idf应用一：类目关键词的提取

这里我尝试使用改进的tf-idf来找出美食内容下CTR高的关键词。因此按照一定的划分规则将美食内容划分成高CTR内容集合，和低CTR内容集合两类。

**核心思想**：一个词在某个类目出现的频率要显著高于在其他类目出现的频率，那么这样的词可以看作是这个类目下的特征词。

采用方案二为此分别计算了每个词在两个类目下的IDF，然后TF就是每个词在这个类目下出现的文档数量。 仅按照IDF排序会得到这样的类似结果：

![](https://3676603176-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ln2Cwa30IhAwp_pKAP9%2F-Ln5nB5C7iMXUqYaYDH2%2F-Ln5nzXDaRSKxELZWKto%2Fimage.png?alt=media\&token=7d446656-d3f5-4d94-b7d8-e41eca18a391)

看到得到的都是些生僻词，因此我们就考虑引入tf来缓解这样的情况了。得到的结果： &#x20;

![](https://3676603176-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ln2Cwa30IhAwp_pKAP9%2F-Ln5nB5C7iMXUqYaYDH2%2F-Ln5o28smw78w60LdagC%2Fimage.png?alt=media\&token=c66a689b-db2f-412c-81a6-ccc58bd9d263)

发现很多没有特点的高频词漏出了，说明词的TF频次造成的影响太大了，于是考虑也用log2来处理一下TF再和IDF相乘吧，得到： &#x20;

![](https://3676603176-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ln2Cwa30IhAwp_pKAP9%2F-Ln5nB5C7iMXUqYaYDH2%2F-Ln5o5YKUFwa4pYmRfOv%2Fimage.png?alt=media\&token=7198253d-4513-43c5-b235-fa64a2ec19bd)

效果明显好多了。得到的词非常符合相关内容在平台上的表现。

不过上述做法多少还是有拍脑袋的成分，实际上我最早挖类目关键词的时候也是按照类似的思想计算了IDF。然后卡了个阈值，再根据TF筛选，效果也还行。区别就在于一个是按照TF和IDF的乘积去作为判别依据，一个是按照阈值去筛选，但是本质上都算人为设定的规则，因为TF和IDF乘积也是需要定各自的影响程度的，比如上面我就发现求个log再乘效果要好很多。

### 5.改进tf-idf应用二：热点发现

先思考下什么是热点，热点显然是最近突然大量出现的内容，找出这样的内容我想的有两种方案。

#### 方案一

根据时间划分两个类，比如过近一周的内容和历史内容对比，这其实就类似之前的做法划分了两个类。然后利用类目关键词的思想找出近一周内容里最重要的词，就是热点词

#### 方案二

先对最近一段时间的内容进行聚类(可以使用embedding或者tfidf的bow)，然后计算每个cluster下的最重要的词。理想情况下同一类的热点内容就会在聚集在某个cluster。得到它的关键词就可以得到热点的特征。因为直接去看每个不同的cluster是很耗费人力的，而直接提炼出来的cluster关键词更加直观。

总的来说，基于tfidf的热点发现本质上还是类似于找类目关键词的。只是这里的“类目”是更宽泛的类目概念，可以是最近一周和历史的对比，可以是聚类产生的类目等等。

### 6.总结

本文总结了几种改进tfidf的方案，并在此方案的基础上实现了类目关键词的提取，并且推广到了更宽泛的“类目”关键词挖掘-热点挖掘上。不管怎么说，tfidf概念上还是比较简单的。实际使用的时候可以按照需要做各种变形，比如说：

* 我要找类目关键词，显然就是一个词在这个类目下出现很多，在其他类目出现少
* 我要找同一个类目下的不同内容的关键词，显然更应该侧重在类目下出现少的词。比如“吃饭”在区分美食和化妆时很重要，但如果全是美食内容，“吃饭”这个词就没啥意义了。

**核心思想**：明确你要划分内容集合时的依据，然后选择最重要的因素，有针对性的对关键词进行加权。

后续会尝试一下再ngram上面的效果，毕竟依靠分词太不可控了。很多热点词、新词，传统的分词工具根本没办法保证能分出来。

还有就是无监督实在是没办法，有足够的标注数据还是有监督方法效果好。

本来研究IDF是在思考改进对内容的打标签，平时对内容打标签经常都直接关键词匹配。现在想想idf在打标签的时候好像意义不是很大，idf还是适合在无监督提取内容关键词的时候让关键词自己露出。而打标签是在给定关键词的基础上做的，基本上关键词出现了，就可以考虑打上，至于准确性在于判断关键词出现的语境，是否上下文也是很符合的。很符合说明这个内容是附带了足够关键词相关的描述的，而不仅仅是提到一个词。在这里用IDF对关键词加权好像还不如直接统计关键词出现的频次。除非一个标签给了多个关键词，那IDF加权可以衡量不同关键词的权重，防止一些过于宽泛的关键词导致无意义的tag召回。

这样看好像IDF还是有点意义的，不过只是在同一个tag的维度，用来衡量不同内容和这个tag的符合程度的。

### 参考文献

\[1] [基于改进TF\_IDF的文本信息热点话题发现](http://www.doc88.com/p-1961690053205.html) - 薛征

\[2] [一种基于改进TF\_IDF函数的文本分类方法](http://xueshu.baidu.com/usercenter/paper/show?paperid=2ee96cefece826fb7efd8d8574fc8c20\&site=xueshu_se) - 卢中宁&#x20;

\[3] [应用于文本分类问题的TF-IDF改进方法](https://blog.csdn.net/fyfmfof/article/details/44034401)
