MapReduce计算反文档频率IDF(Python实现)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012369535/article/details/88018178

一、基本概念

     词频(TF,Term Frequency):一篇文章中某个词的出现次数。TF=某个词在文章中出现的次数/文章的总词数,或者TF=某个词在文章中出现的次数/该文出现次数最多的词的次数。
     反文档频率IDF:在词频的基础上,赋予每个词的权重,进一步体现该词的重要性。IDF=log([语料库的文档总数]/[包含该词的文档数+1])。
     TF-IDF=词频(TF)* 反文档频率(IDF),可以看出TF-IDF与一个词在文档中出现的次数成正比,与包含该词的文档数成反比。某个词对文章的重要性越高,该值越大,于是排在前面的几个词,就是这篇文章的关键词。
     TF-IDF可运用于计算两篇文章的相似度:

  • 使用TF-IDF算法,找出两篇文章的关键词;
  • 每篇文章各取出若干个关键词(比如20个),合并成一个集合(不重复),计算每篇文章对于这个集合中的词的词频;
  • 生成两篇文章各自的词频向量(两个向量每个维的顺序要保持一致,可与集合顺序一致);
  • 计算两个向量的余弦相似度,值越大就表示越相似。

二、IDF实践

     实践中选取已进行中文分词后的508篇文章,其内容如下:
在这里插入图片描述

  • convert.py:由于508篇文章需要频繁的读取每一篇,增加了磁盘IO操作,故先将其内容合并为一个文件中,合并代码如下。
import os
import sys

file_path_dir = sys.argv[1]       %获取存放508篇文章的目录

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())    %将每篇文章里的所有行内容去首位空格和换行符后添加进List集合

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

    file_name += 1

     然后执行以下命令,将所有文章合并到idf_input.data文件中,该文件的每一行为每一篇文章的内容,共508行

[root@master tfidf_python]# python convert.py input_tfidf_dir > idf_input.data
  • map.py:对所有文章的单词作map处理,每篇文章的单词需作去重处理,这样再对每个单词后添置1,表示包含该单词的文章数。
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'])

     map的输出结果部分如下:
在这里插入图片描述

  • reduce.py:对map输出的结果,合并相同的单词key的value值,统计包含该词的文档总数,计算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)])    %打印最后一个单词的idf值

     通过以下命令测试mapreduce:加入了人工排序,模拟MapReduce的shuffle里的排序

[root@master tfidf_python]# cat idf_input.data | python map.py | sort -k1 | python red.py > red.tmp
  • 结果:
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u012369535/article/details/88018178