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

本文深入探讨了TF-IDF算法的基本原理,包括词频(TF)和反文档频率(IDF)的概念,以及如何利用TF-IDF算法计算文档关键词和评估文档间的相似度。此外,还介绍了TF-IDF在实际应用中的具体步骤,从文档预处理到计算IDF值的全过程。
摘要由CSDN通过智能技术生成

一、基本概念

     词频(TF,Term Frequency):一篇文章中某个词的出现次数。TF=某个词在文章中出现的次数/文章的总词数,或者TF=某个词在文章中出现的次数/该文章出现次数最多的词的次数。
T F = 某 个 词 在 文 章 中 出 现 的 次 数 文 章 的 总 词 数 = 某 个 词 在 文 章 中 出 现 的 次 数 该 文 章 出 现 次 数 最 多 的 词 的 次 数 TF=\frac{某个词在文章中出现的次数}{文章的总词数}=\frac{某个词在文章中出现的次数}{该文章出现次数最多的词的次数} TF==
     反文档频率IDF:在词频的基础上,赋予每个词的权重,进一步体现该词的重要性。IDF=log([语料库的文档总数]/[包含该词的文档数+1])。
I D F = l o g 语 料 库 的 文 档 总 数 包 含 该 词 的 文 档 数 + 1 IDF=log\frac{语料库的文档总数}{包含该词的文档数+1} 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)]) # 格式:文章id + ‘\t’ + 该文章第一行 + ' ' + 该文章第二行...

    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值,reduce的前提是map的输出结果已按key(word)进行了排序
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:  # 遍历第一行map结果
        current_word = word
    if current_word != word:  # 遍历到不同的word,统计当前word的IDF值
        idf = math.log(float(docs_cnt) / (float(sum) + 1.0))
        print '\t'.join([current_word, str(idf)])
        current_word = word
        sum = 0 # 记录当前word被多少篇文章包含

    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
  • 结果:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值