TF—IDF

TF-IDF

TF-IDF(Term Frequency-Inverse Document Frequency, 词频-逆文本频率)。TF指词频,IDF指的是逆文本频率。TF-IDF是一种用于信息检索与数据挖掘的常用加权技术,可以评估一个词在一个文件集或者一个语料库中对某个文件的重要程度。一个词语在一篇文章中出现的次数越多,同时在所有文章中出现的次数越少,越能够代表该文章的中心意思,这就是TF-IDF的含义。

词频(Term Frequency ,TF)指的是一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般是词频除以文章总词数),来防止这个词偏向内容较长文件。比如:同一个词语在长文件里可能会比短文件有更高的词频。

                 

逆向文本频率(Inverse Document Frequency,IDF),主要思想是在语料库中包含某个词条的文档越少,该词条IDF越大,说明这个词就有很强的类别区分能力。通常某个词语的IDF可以由语料库中文件的总数量除以包含该词语的文件数目,再将得到的商取对数决定。

 

 

分母加1主要是避免这个单词在语料库文章中没有出现,避免分母为0。这样当一个词语在语料库少数文章中出现,该词语对应的IDF值越大,当一个词语在大多数文章中都出现,那么该词语对应的IDF值会越小。

这样,某个词条的TF-IDF的值为 ,即某一个文件中高频出现的词条,以及该词条在整个语料库文件中低频出现的现象,就可以产生高权重的TF-IDF,因此,TF-IDF倾向过滤掉常见的词语,保留重要的词语。即:字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

案例:

object KMeans11 {

  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName("KMeans1").setMaster("local[*]")
    val sc = new SparkContext(conf)

    val rdd = sc.textFile("./original.txt")
    /**
     * wordRDD 是一个KV格式的RDD
     * 	K:微博ID
     * 	V:微博内容分词后的结果 ArrayBuffer
     */
    var wordRDD = rdd.mapPartitions(iterator => {
      val list = new ListBuffer[(String, ArrayBuffer[String])]
      while (iterator.hasNext) {
        //创建分词对象
        val analyzer = new IKAnalyzer(true)
        val line = iterator.next()
        val textArr = line.split("\t")
        val id = textArr(0)
        val text = textArr(1)
        //分词
        val ts : TokenStream = analyzer.tokenStream("", text)
        val term : CharTermAttribute = ts.getAttribute(classOf[CharTermAttribute])
        ts.reset()
        
        val arr = new ArrayBuffer[String]
        while (ts.incrementToken()) {
          arr.+=(term.toString())
        }
        
        list.append((id, arr))
        analyzer.close()
      }
      list.iterator
    })
    wordRDD = wordRDD.cache() 
    

    /**
     * HashingTF 使用hash表来存储分词
     * 
     * 1000:只是计算每篇微博中1000个单词的词频   最大似然估计思想
     */
    val hashingTF: HashingTF = new HashingTF(1000)

    /**
     * tfRDD
     * K:微博ID
     * V:Vector(tf,tf,tf.....)
     * 
     * hashingTF.transform(x._2) 计算分词频数(TF)
     */
    val tfRDD = wordRDD.map(x => {
      (x._1, hashingTF.transform(x._2))
    })

    /**
     * 得到IDFModel,要计算每个单词在整个语料库中的IDF
     */
    val idf: IDFModel = new IDF().fit(tfRDD.map(_._2))

    /**
     * K:weibo ID
     * V:每一个单词的TF-IDF值
     * tfIdfs这个RDD中的Vector就是训练模型的训练集
     * 
     */
    val tfIdfs: RDD[(String, Vector)] = tfRDD.mapValues(idf.transform(_))
    
    //设置聚类个数
    val kcluster = 20
    val kmeans = new KMeans()
    kmeans.setK(kcluster)
    //使用的是kemans++算法来训练模型
    kmeans.setInitializationMode("k-means||")
    //设置最大迭代次数
    kmeans.setMaxIterations(100)

    val kmeansModel: KMeansModel= kmeans.run(tfIdfs.map(_._2))
    //    kmeansModel.save(sc, "d:/model001")

    //打印模型的20个中心点
    println(kmeansModel.clusterCenters)

    /**
     * 模型预测
     */
    val modelBroadcast = sc.broadcast(kmeansModel)
    /**
     * predicetionRDD KV格式的RDD
     * 	K:微博ID
     * 	V:分类号
     */
    val predicetionRDD = tfIdfs.mapValues(sample => {
      val model = modelBroadcast.value
      model.predict(sample)
    })
//    predicetionRDD.saveAsTextFile("d:/resultttt")

    /**
     * 总结预测结果
     * tfIdfs2wordsRDD:kv格式的RDD
     * K:微博ID
     * V:二元组(Vector(tfidf1,tfidf2....),ArrayBuffer(word,word,word....))
     */
    val tfIdfs2wordsRDD = tfIdfs.join(wordRDD)
    /**
     * result:KV
     * K:微博ID
     * V:(类别号,(Vector(tfidf1,tfidf2....),ArrayBuffer(word,word,word....)))
     */
    val result = predicetionRDD.join(tfIdfs2wordsRDD)

    /**
     * 查看0号类别中tf-idf比较高的单词,能代表这类的主题
     */
    result
      .filter(x => x._2._1 == 0)
      .flatMap(line => {
        
        val tfIdfV: Vector = line._2._2._1
        val words: ArrayBuffer[String] = line._2._2._2
        val tfIdfA: Array[Double] = tfIdfV.toArray
        
        val wordL = new ListBuffer[String]()
        val tfIdfL = new ListBuffer[Double]()
        var index = 0
        for(i <- 0 until tfIdfA.length ;if tfIdfV(i) != 0){
          wordL.+=(words(index))
          tfIdfL.+=(tfIdfA(index))
          index += 1
        }
        println(wordL.length + "===" + tfIdfL.length)
        val list = new ListBuffer[(Double, String)]
        for (i <- 0 until wordL.length) {
          list.append((tfIdfV(i), words(i)))
        }
        list
      })
      .sortBy(x => x._1, false)
      .map(_._2)
      .distinct()
      .take(30).foreach(println)
    sc.stop()
  }
}

 

你可能感兴趣的:(机器学习)