TF-IDF原理及使用

15 篇文章 0 订阅
10 篇文章 1 订阅

一. 什么是TF-IDF

TF-IDF(Term Frequency-Inverse Document Frequency, 词频-逆文件频率).

是一种用于资讯检索与资讯探勘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

上述引用总结就是, 一个词语在一篇文章中出现次数越多, 同时在所有文档中出现次数越少, 越能够代表该文章.

这也就是TF-IDF的含义.

词频 (term frequency, TF) 指的是某一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般是词频除以文章总词数), 以防止它偏向长的文件。(同一个词语在长文件里可能会比短文件有更高的词频,而不管该词语重要与否。)

但是, 需要注意, 一些通用的词语对于主题并没有太大的作用, 反倒是一些出现频率较少的词才能够表达文章的主题, 所以单纯使用是TF不合适的。权重的设计必须满足:一个词预测主题的能力越强,权重越大,反之,权重越小。所有统计的文章中,一些词只是在其中很少几篇文章中出现,那么这样的词对文章的主题的作用很大,这些词的权重应该设计的较大。IDF就是在完成这样的工作.

公式:


逆向文件频率 (inverse document frequency, IDF) IDF的主要思想是:如果包含词条t的文档越少, IDF越大,则说明词条具有很好的类别区分能力。某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到。

公式如下:(分母之所以加一,是为了防止分母为零)

              

        某一特定文件内的高词语频率,以及该词语在整个文件集合中的低文件频率,可以产生出高权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。

                                      


                                    TF-IDF与一个词在文档中的出现次数成正比, 与包含该词的文档数成反比。

二. 一个实例

参考: http://www.ruanyifeng.com/blog/2013/03/tf-idf.html

这里写图片描述

三. Spark 中 TF-IDF 的实现

1. 基于spark1.4.1 ml算法包的TF-IDF算法

// 参考自spark官网教程 http://spark.apache.org/docs/latest/ml-features.html#tf-idf
// In the following code segment, we start with a set of sentences. 
// We split each sentence into words using Tokenizer. For each sentence (bag of words),
// we use HashingTF to hash the sentence into a feature vector. We use IDF to rescale
// the feature vectors; this generally improves performance when using text as features. // Our feature vectors could then be passed to a learning algorithm.

import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.ml.feature.{Tokenizer,HashingTF, IDF}
import org.apache.spark.mllib.linalg.{Vectors, Vector}
// 创建实例数据
val sentenceData = sqlContext.createDataFrame(Seq(
  (0, "Hi I heard about Spark"),
  (0, "I wish Java could use case classes"),
  (1, "Logistic regression models are neat")
)).toDF("label", "sentence")

//  scala> sentenceData.show
//  +-----+--------------------+
//  |label|            sentence|
//  +-----+--------------------+
//  |    0|Hi I heard about ...|
//  |    0|I wish Java could...|
//  |    1|Logistic regressi...|
//  +-----+--------------------+

//句子转化成单词数组
val tokenizer = new Tokenizer().setInputCol("sentence").setOutputCol("words")
val wordsData = tokenizer.transform(sentenceData)

// scala> wordsData.show
//  +-----+--------------------+--------------------+
//  |label|            sentence|               words|
//  +-----+--------------------+--------------------+
//  |    0|Hi I heard about ...|ArrayBuffer(hi, i...|
//  |    0|I wish Java could...|ArrayBuffer(i, wi...|
//  |    1|Logistic regressi...|ArrayBuffer(logis...|
//  +-----+--------------------+--------------------+

// hashing计算TF值,同时还把停用词(stop words)过滤掉了. setNumFeatures(20)表最多20个词
val hashingTF = new HashingTF().setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(20)
val featurizedData = hashingTF.transform(wordsData)

// scala> featurizedData.show
//  +-----+--------------------+--------------------+--------------------+
//  |label|            sentence|               words|         rawFeatures|
//  +-----+--------------------+--------------------+--------------------+
//  |    0|Hi I heard about ...|ArrayBuffer(hi, i...|(20,[5,6,9],[2.0,...|
//  |    0|I wish Java could...|ArrayBuffer(i, wi...|(20,[3,5,12,14,18...|
//  |    1|Logistic regressi...|ArrayBuffer(logis...|(20,[5,12,14,18],...|
//  +-----+--------------------+--------------------+--------------------+


val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
val idfModel = idf.fit(featurizedData)
val rescaledData = idfModel.transform(featurizedData)
// 提取该数据中稀疏向量的数据,稀疏向量:SparseVector(size,indices,values)
// rescaledData.select("features").rdd.map(row => row.getAs[linalg.Vector](0)).map(x => x.toSparse.indices).collect
rescaledData.select("features", "label").take(3).foreach(println)

//  [(20,[5,6,9],[0.0,0.6931471805599453,1.3862943611198906]),0]
//  [(20,[3,5,12,14,18],[1.3862943611198906,0.0,0.28768207245178085,0.28768207245178085,0.28768207245178085]),0]
//  [(20,[5,12,14,18],[0.0,0.5753641449035617,0.28768207245178085,0.28768207245178085]),1]
// 其中,20是标签总数,下一项是单词对应的hashing ID.最后是TF-IDF结果

2.基于RDD的MLlib包中的TF_IDF算法

 
//参考: http://spark.apache.org/docs/1.4.1/mllib-feature-extraction.html#tf-idfark.mllib.feature.HashingTF
//进阶参考
//http://blog.csdn.net/jiangpeng59/article/details/52786344

import org.apache.spark.mllib.linalg.Vector
val sc: SparkContext = ...

// Load documents (one per line).
val documents: RDD[Seq[String]] = sc.textFile("...").map(_.split(" ").toSeq)

val hashingTF = new HashingTF()
val tf: RDD[Vector] = hashingTF.transform(documents)
tf.cache()
val idf = new IDF().fit(tf)
val tfidf: RDD[Vector] = idf.transform(tf)

3、基于python mapreduce的TF_IDF计算

convert.py(将所有文件内容汇总到一个数据文件中)

import os
import sys

file_path_dir = sys.argv[1]

def read_file_handler(f):
    fd = open(f, 'r')
    return fd

file_name = 0
for fd in os.listdir(file_path_dir):
    file_path = file_path_dir + '/' + fd

    content_list = []

    file_fd = read_file_handler(file_path)
    for line in file_fd:
        content_list.append(line.strip())

    print '\t'.join([str(file_name), ' '.join(content_list)])

    file_name += 1

map.py(对所有文章按一定规律进行切分)

import sys

for line in sys.stdin:
    ss = line.strip().split('\t')
    if len(ss) != 2:
        continue
    file_name, file_content = ss
    word_list = file_content.strip().split(' ')

    word_set = set(word_list)

    for word in word_set:
        print '\t'.join([word, '1'])

red.py(对文章进行统计,并求出IDF)

import sys
import math

current_word = None
sum = 0

docs_cnt = 508

for line in sys.stdin:
    ss = line.strip().split('\t')
    if len(ss) != 2:
        continue

    word,val = ss
    if current_word == None :
        current_word = word
    if current_word != word:
        idf = math.log(float(docs_cnt) / (float(sum) + 1.0))
        print '\t'.join([current_word, str(idf)])
        current_word = word
        sum = 0

    sum += int(val)

idf = math.log(float(docs_cnt) / (float(sum) + 1.0))
print '\t'.join([current_word, str(idf)])

tf_idf.py(求出最终的tf_idf)

import sys

idf_dic_path = sys.argv[1]
docs_path = sys.argv[2]
inout_docid = sys.argv[3]
input_token = sys.argv[4]

idf_dict = {}
with open(idf_dic_path, 'r') as fd:
    for line in fd:
        ss = line.strip().split('\t')
        if len(ss) != 2:
            continue
        token, idf = ss
        idf_dict[token] = float(idf)

tf_dict = {}
sum_content = 0
with open(docs_path, 'r') as fd:
    for line in fd:
        ss = line.strip().split('\t')
        if len(ss) != 2:
            continue
        docid, content = ss
        if docid != docid:
            continue
        for token in content.strip().split(' '):
            if token not in tf_dict:
                tf_dict[token] = 1
            else:
                tf_dict[token] += 1
            sum_content += 1


if (input_token not in tf_dict) or (input_token not in idf_dict):
    print "no found token"
    sys.exit(-1)

tfidf = tf_dict[input_token] * idf_dict[input_token] / float(sum_content)
print '\t'.join([inout_docid, input_token, tfidf])

四. 参考

http://blog.csdn.net/google19890102/article/details/29369793
http://www.ruanyifeng.com/blog/2013/03/tf-idf.html
http://www.cnblogs.com/rausen/p/4142838.html
http://blog.csdn.net/jiangpeng59/article/details/52786344

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值