Spark-特征抽取(TF-IDF)

来源:互联网 发布:linux recovery mode 编辑:程序博客网 时间:2024/05/20 19:32

Spark特征抽取,基于scala实现TF-IDF实例。
特征抽取:从原始数据中抽取特征。

TF-IDF原理

TF-IDF(term frequency–inverse document frequency)是一种用于资讯检索与资讯探勘的常用加权技术, TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TFIDF实际上是:TF * IDF,TF词频(Term Frequency),IDF反文档频率(Inverse Document Frequency)。TF表示词条在文档d中出现的频率。IDF的主要思想是:如果包含词条t的文档越少,也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力。如果某一类文档C中包含词条t的文档数为m,而其它类包含t的文档总数为k,显然所有包含t的文档数n=m + k,当m大的时候,n也大,按照IDF公式得到的IDF的值会小,就说明该词条t类别区分能力不强。但是实际上,如果一个词条在一个类的文档中频繁出现,则说明该词条能够很好代表这个类的文本的特征,这样的词条应该给它们赋予较高的权重,并选来作为该类文本的特征词以区别与其它类文档。这就是IDF的不足之处。

具体的定义

假设t表示一个词,d表示一片文档,D是语料库中文档总数。
词频TF(t,d)是某个词t在文档d中出现的次数。
文档频率DF(t,D)是包含词t的文档d的数目。
如果我们仅使用词频来衡量重要性,则很容易过分强调那些出现非常频繁但携带很少与文档相关信息量的词。
比如英语中的“a”、“the”和“of”。如果一个词在在语料库中出现非常频繁,意味着它更不能携带特定文档的特定信息。逆文档频率就是一个用于度量一个词能提供多少信息量的数值:

IDF(t,D)=log |D|/(DF(t,D)+1)TFIDF(t,d,D)=TF(t,d)×IDF(t,D)

在SparkML库中,TF-IDF被分为两部分:TF和IDF
TF:HashingTF 是一个Transformer,在文本处理中,接收词条的集合然后把这些集合转化成固定长度的特征向量。这个算法在哈希的同时会统计各个词条的词频。
IDF:IDF是一个Estimator,在一个数据集上应用它的fit()方法,产生一个IDFModel。 该IDFModel 接收特征向量(由HashingTF产生),然后计算每一个词在文档中出现的频次。IDF会减少那些在语料库中出现频率较高的词的权重。

具体的Spark实例

tfidf.txt的文件如下:

i heard about spark and i love sparki wish java could use case classeslogistic regression models are neat

实例代码如下:

package FeatureExtractionAndTransformationimport org.apache.spark.mllib.feature.{IDF, HashingTF}import org.apache.spark.{SparkContext, SparkConf}/** * Created by xudong on 2017/5/24. */object TFIDFLearning {  /**   * TF-IDF是一种简单的文本特征提取算法   * 词频tf:某个关键词在文本中出现的次数   * 逆文档频率idf:大小与一个词的常见程度成反比   * tf=某个词在文章中出现的次数/文章的总词数   * idf=log(查找的文章总数/(包含该词的文章数+1))   * tf-idf=tf * idf   * 未考虑去除停用词(辅助词副词介词等)和语义重构(数据挖掘,数据结构 =》数据,挖掘;数据,结构  50%)   *   */  def main(args: Array[String]) {    val conf = new SparkConf().setAppName("tf-idfExamples").setMaster("local")    val sc=new SparkContext(conf)    //加载文档(one per line)一行是一个文档    val documents=sc.textFile("e:/tfidf.txt").map(_.split(" ").toSeq)    //HashingTF是一个Transformer,文本处理中接收词条的集合然后把这些集合转换成固定长度的特征向量    //这个算法在哈希的同时会统计各个词条的词频    val hashingTF=new HashingTF()    val tf=hashingTF.transform(documents)    tf.cache()    //idf是一个Estimator,在一个数据集上应用fit方法,产生一个IDFModel    //该IDFModel接收特征向量(由HashingTF产生),然后计算每一个词在文档中出现的频次    //IDF会减少那些在语料库中出现频率较高的词的权重。    /**     * Spark.mllib 中实现词频率统计使用特征hash的方式,原始特征通过hash函数,映射到一个索引值。     * 后面只需要统计这些索引值的频率,就可以知道对应词的频率。     * 这种方式避免设计一个全局1对1的词到索引的映射,这个映射在映射大量语料库时需要花费更长的时间。     * 但需要注意,通过hash的方式可能会映射到同一个值的情况,即不同的原始特征通过Hash映射后是同一个值。     * 为了降低这种情况出现的概率,我们只能对特征向量升维。     * i.e., 提高hash表的桶数,默认特征维度是 2^20 = 1,048,576.     */     tf.foreach(println)    /**     * (1048576,[105,96727,182130,336781,585782,586461],[2.0,1.0,1.0,1.0,1.0,2.0])     * (1048576,[105,79910,109090,116103,479425,503975,949040],[1.0,1.0,1.0,1.0,1.0,1.0,1.0])     * (1048576,[96852,225888,231466,491585,748138],[1.0,1.0,1.0,1.0,1.0])     * tf 的输出值 1048576表示的是hash表的桶数(默认值)     * 105,96727等代表单词的hash值,后面是出现的次数     */    val idf=new IDF().fit(tf)    val tfidf =idf.transform(tf)    println("tfidf: ")    tfidf.foreach(x => println(x))  /**tdidf--结果输出     * (1048576,[105,96727,182130,336781,585782,586461],[0.5753641449035617,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453,1.3862943611198906])     * (1048576,[105,79910,109090,116103,479425,503975,949040],[0.28768207245178085,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453])     * (1048576,[96852,225888,231466,491585,748138],[0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453])     *///后面的数值是每个单词的在各文档的tfidf值    //支持忽略词频低于文档最小数,需要把minDocFreq这个数传给IDF函数。    // 在此情况下,对应的IDF值设置为0/*  val idfIgnore=new IDF(minDocFreq = 2).fit(tf)    val idfIgnore=new IDF(minDocFreq = 2).fit(tf)    val tfidfIgnore=idfIgnore.transform(tf)    println("tfidfIgnore: ")    tfidfIgnore.foreach(x => println(x))*/    sc.stop()  }}
阅读全文
0 0