NPL-TFIFD

TFIDF

一 简介

1、TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。

2、TF

TF意思是词频(Term Frequenc),某个词在文章出现的次数。

停用词:词频也不是绝对的,像出现次数最多的词是----"的"、"是"、"在"----这一类最常用的词。它们叫做"停用词"(stop words),表示对找到结果毫无帮助、必须过滤掉的词。

3、IDF

IDF意思是反文本频率(Inverse Document Frequency),在词频的基础上,赋予每一个词的权重,进一步体现该词的重要性。

比如:

       最常见的词("的"、"是"、"在")给予最小的权重,

  较常见的词("中国")给予较小的权重,

  较少见的词("维基"、"养殖")给予较大的权重。

IDF是反文频率,主要是相反的,它的大小与一个词的常见程度成反比。

4、TFIDF

TF与IDF相乘,就得到一个TF-IDF值,某个词对文章的重要性越大,它的TFIDF值越大;

于是,排在前面的几个词就是这篇文章的关键词。

TF-IDF 目的就是提取关键词。

二 计算步骤

1、计算词频

  词频(TF) = 某个词在文章中的出现次数

文章有长短之分,为了便于不同文章的比较,做"词频"标准化。

  词频(TF) = 某个词在文章中的出现次数 / 文章总词数

或者 词频(TF) = 某个词在文章中的出现次数 / 拥有最高词频的词的次数

2、某个词在文章中的出现次数

这时,需要一个语料库(corpus),用来模拟语言的使用环境。

反文档频率(IDF) = log(语料库的文档总数/包含该词的文档总数+1)

3、计算TF-IDF

  TF-IDF = 词频(TF) * 逆文档频率(IDF)

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

三 例子

假如一篇文件的总词语数是100个,而词语“母牛”出现了3次,那么“母牛”一词在该文件中的词频就是3/100=0.03。一个计算文件频率 (IDF) 的方法是文件集里包含的文件总数除以测定有多少份文件出现过“母牛”一词。所以,如果“母牛”一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是 lg(10,000,000 / 1,000)=4。最后的TF-IDF的分数为0.03 * 4=0.12。

 

四 实际-求IDF值

有500多篇文章,开发MR,实现每个词语的IDF值。

[root@master tfidf_test]# ls input_tfidf_dir/ | wc -l

508

1、把508篇文章汇总到一篇文章里面,每篇文章一行,一共有508行

代码实现

[root@master tfidf_test]# cat convert.py 
#coding=utf-8
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)])
    #name跟文章内容是按制表符分隔,数值型转换为字符串,文章内容用空格分隔
    file_name += 1
    #一共读多少文章,对应上面的file_name = 0

[root@master tfidf_test]# python convert.py  input_tfidf_dir > idf_input.data

[root@master tfidf_test]# wc -l idf_input.data

508 idf_input.data

这个脚本作用:把文章汇总,做元数据

2、完成map代码

分析:这个map要做什么,完成哪些内容

代码思路:有一堆文章,文章里面的某个词出现,那就打1,没出现就打0,其实0的也不用输出了,只要统计有输出的行了

[root@master tfidf_test]# vim map.py 

#coding=utf-8
import sys

for line in sys.stdin:
    ss = line.strip().split('\t')
    #数组ss,\t是对应输入数据
    if len(ss) != 2:
        continue
    file_name, file_content = ss
    word_list = file_content.strip().split(' ')
    #文章全部分词写入word_list
    word_set = set(word_list)
    #去重,因为一个词在当前文章只能出现一次
    for word in word_set:
        print '\t'.join([word, '1'])

不需要文章id,因为只是求idf,只需要知道语料库的文档总数,这里是508,还有包含该词的文档数;

map只是是先切分出每篇文章的单词个数。

一个词对于不同的文章,tf值不同,tfidf值也就不同,需要指定文章id,Idf是个全局概率,不需要文章id。

3、完成red代码

Map已经把每篇文章的单词已经切分了,没有统计每个单词的个数,red就相当于再写一个wordcount。

[root@master tfidf_test]# cat red.py 
#coding=utf-8
import sys
import math
#结果是求log,需要数学模块
current_word = None
#定义一个变量,用来记录读取的单词
sum = 0
#定义一个变量,用来记录cur_word的数量
docs_cnt = 508
#分子,语料库文档总数
for line in sys.stdin:
#标准输入,循环
    ss = line.strip().split('\t')
    #定义数组,对应数据\t分隔
    if len(ss) != 2:
        continue
    word, val = ss
    #把ss数组里的两个值,单词和数量分别赋值给word和cnt
    if current_word == None:
        current_word = word
    #把刚读取的word赋值给全局变量,记录一下,用来判断下次读取的是否和这个相同
    if current_word != word:
    #如果和全局变量不同,说明cur_word这个单词的统计已经完了
        idf = math.log(float(docs_cnt) / (float(sum) + 1.0))
        #计算idf值.+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)])
#避免数据遗漏

4、求IDF值

[root@master tfidf_test]# cat idf_input.data | python map.py |sort -k1 | python red.py > IDF

[root@master tfidf_test]# cat IDF | sort -k2 | head

分享      -0.00196656897204

搜狐      -0.00196656897204

的   0.0019704439873

在   0.0927543934922

了   0.123458559836

是   0.15513541649

一   0.195000015054

有   0.211888233082

和   0.234029358959

也   0.251595682677

[root@master tfidf_test]# cat idf | sort -k2 | tail

作弊      5.53733426702

作物      5.53733426702

做菜      5.53733426702

坐标      5.53733426702

坐等      5.53733426702

坐视      5.53733426702

坐收      5.53733426702

坐椅      5.53733426702

坐庄      5.53733426702

坐姿      5.53733426702

5、求TFIDF

[root@master tfidf_test]# cat tfidf.demo.py 
#coding:utf-8
import  sys

idf_dict_path = sys.argv[1]
#传输词表	
docs_path = sys.argv[2]
input_docid = sys.argv[3]
#传具体的文章
input_token = sys.argv[4]
#传输token

idf_dict = {}
with open(idf_dict_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 != input_docid:
			continue
		for token in content.strip().split(' '):
       #遍历content,求token
			if token not in tf_dict:
				tf_dict[token] = 1
           #如果token不在词表里面,说明是第一次出现,token=1
			else:
				tf_dict[token] += 1
           #否则token个数+1
           sum_content += 1
           #统计文章总词数
#这里完成之后,就把指定的篇文章里面的token值,放到tf_dict里了

if (input_token not in tf_dict) or (input_token not in idf_dict):
     print "no found token"
     ssy.exit(-1)
     #直接退出
tfidf = tf_dict[input_token] * idf_dict[input_token]/float(sum_content)
print '\t'.join([input_docid,input_token, str(tfidf)])

求某一个词的TFIDF值,part-00000是集群跑出的idf值数据。

[root@master tfidf_test]# python tfidf.demo.py part-00000 idf_input.data 9 手机
9    手机    0.0257687038165

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值