引言
TF-IDF是一种简单的特征提取算法。
在全文检索功能开发时,一定会设计到很多字段的搜索, 但是一般我们只需要搜索文章特定的关键字即可搜索出来?但是什么是关键字?关键字又是如何计算出来的呢?比如如下数据表信息中,如果提取文章的关键字呢?
TF-IDF算法
TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF是词频(Term Frequency),IDF是逆文本频率指数(Inverse Document Frequency)。
TF-IDF思想也就是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。如下表格,如果搜索C罗
就只能检索第一条数据。如果是搜索北京
就无法进行区分。说明北京不适合分类。
title | content |
---|---|
官方:皮尔洛出任尤文新帅 合同为期2年 | 北京 时间8月10日讯 尤文图斯俱乐部官方消息,皮尔洛出任俱乐部一线队新任主帅,双方签约至2022年6月。尤文在欧冠被里昂淘汰之后,第2天即官宣萨里下课,复赛后的带队表现以及与C罗 等大牌球星的相处都存在争议 |
易建联罚球绝杀!广东险胜北京总分2-1进决赛 | 北京 8月8日,CBA季后赛半决赛京粤大战第三场展开决胜大战。广东以88-85战胜北京,从而以总比分2-1淘汰北京队挺进总决赛,将与辽宁争夺总冠军。这也是广东队队史第15次打进总决赛。易建联竟然… |
韩德君35+20辽宁险胜新疆 总分2-0进决赛 | 北京 时间8月7日,CBA下半区半决赛展开第二场争夺,首战获胜的辽宁迎战全华班的新疆。齐麟得到22分创个人职业新高,韩德君砍下35分20篮板,郭艾伦贡 |
计算公式:
D为文档总数或者可以为集合数,DF(t,D)表示在集合D有词语t的文档数。分式上下都+1防止有0的情况。源码中log即以e为底而不是以10为底,所以如果是自己计算进行对比的话,使用ln。
如上公式说明在集合D中文档d中词语t的TFIDF的值 等于 词语t在文档d的频率乘以词语t在集合D的逆文本指数。
举例说明
tfidf.txt
我中了一个奖品
我爱吃苹果
你是我的小苹果
scala代码
case class ContentBean(content:String,words:Array[String])
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("tfidf")
.master("local[2]")
.getOrCreate();
val path = "C:\\Users\\archermind\\Desktop\\ml-1m\\tfidf.txt"
import spark.implicits._
//加载文件
val input = spark.sparkContext.textFile(path)
//通过BaseAnalysis 进行分词 分词详解 https://github.com/NLPchina/ansj_seg
var content = input
.map(x => ContentBean (x,BaseAnalysis.parse(x).toStringWithOutNature(" ").split(" ")))
.toDF();
//HashingTF计算频率TF
var hashingTF = new HashingTF().setInputCol("words").setOutputCol("rawFeatures")
var featuresDF = hashingTF.transform(content);
val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
// idf = ln((m + 1) / (d(t) + 1)) m文章总数 t含有该词文章数
val idfModel = idf.fit(featuresDF);
var tfidf = idfModel.transform(featuresDF)
// 输入结果
tfidf.show(false)
}
输出结果,由于太长,可复制出来查看。
+--------------+--------------------------+---------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+
|content |words |rawFeatures |features |
+--------------+--------------------------+---------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+
|我中了一个奖品|[我, 中, 了, 一个, 奖品] |(262144,[24380,91015,117468,219629,244828],[1.0,1.0,1.0,1.0,1.0]) |(262144,[24380,91015,117468,219629,244828],[0.6931471805599453,0.6931471805599453,0.6931471805599453,0.0,0.6931471805599453]) |
|我爱吃苹果 |[我, 爱, 吃, 苹果] |(262144,[14800,105739,173195,219629],[1.0,1.0,1.0,1.0]) |(262144,[14800,105739,173195,219629],[0.28768207245178085,0.6931471805599453,0.6931471805599453,0.0]) |
|你是我的小苹果|[你, 是, 我, 的, 小, 苹果]|(262144,[14800,27555,80738,129171,219629,238030],[1.0,1.0,1.0,1.0,1.0,1.0])|(262144,[14800,27555,80738,129171,219629,238030],[0.28768207245178085,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.0,0.6931471805599453])|
+--------------+--------------------------+---------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+
words是分词结果。
rawFeatures是频率信息(262144,[24380,91015,117468,219629,244828],[1.0,1.0,1.0,1.0,1.0])
通过逗号分隔,前两个不需要关心,最后那个是词出现的频率TF。
features前两个也不需要关心,最后是TF-IDF的值。
按照公式,文档集合D为3。
第一个文档中奖品
的频率TF为1。TF-IDF值为ln((3+1)/(1+1)) * 1 = 0.6931471805599453
第二个文档中苹果
的频率TF为1。TF-IDF的值为ln((3+1)/(2+1)) * 1 = 0.287682072451