Spark的TF-IDF实践

一.公式的分析和编写代码的思路:

根据公式,计算TF-IDF首先需要计算TF和IDF,然后在做乘积
在这里插入图片描述

1.TF运算

(1)TF运算的时候,首先需要统计某个单词在该篇文章出现的次数、和统计单词所在那篇文章的单词的总数
在这里插入图片描述
(2)实现思路:在每个文章中对单词进行计数,形成一个(word,count)形式的元组,因为在不同文章中分别计算TF需要用到该单词所在文章单词的数量,所以最后的对于每篇文章我将计数的结果生成如下形式:即结果列表有两个元素,一个元素存储每个单词在文章的计数情况,另一个存储单词的个数
在这里插入图片描述
然后使用map函数对每一篇文章进行计算tf,生成新的结果,并且以元组的形式保存(word,tf),如下图所示。
在这里插入图片描述

2.IDF的计算

(1)IDF的运算需要用到数据中包含的所有文本的数量,以及包含某个单词的文本的数量,因此idf的值实际上并不受某篇文章的影响,他描述的是所有数据集整体的属性,所以并不需要在每一篇文章对分别对某个单词计算,整体计算IDF然后以字典的形式存储,再以共享变量的方式在整个executor上共享即可以减少空间的开销也可以节省计算时间,这一点起初我并没有考虑到。
在这里插入图片描述
(2)文本的总数,可以较为容易获取到,包含word的文本个数整体思路,就是在每篇文章中对单词进行去重形成新的RDD,然后运用word count的思路先将RDD展平,然后map生成键值对,最后reducebykey得到结果
在这里插入图片描述

3.TF_IDF计算

运用得到的TF,IDF字典进行乘积运算

二.代码实现:

1.定义全局共享的数据集

在这里插入图片描述

2.一些用于辅助的函数:

在这里插入图片描述
在这里插入图片描述

3.主函数部分:

在这里插入图片描述

三.代码的执行结果:

在这里插入图片描述
完整代码:

import math
from pyspark import SparkConf,SparkContext
#定义数据集
doc_list = [["hello","world","china","good","spark","good"],
        ["hello","china","china","great","love","china"],
        ["love","spark","spark","good","hello","spark"]
        ]
#计算文档的数目
doc_num = len(doc_list)
#这个函数作用是分别对每篇文章中进行计数,生成类似于[((word1,1),(word2,2)),6]的列表,
#这个列表除了存储单词计数的结果还存储,单词所在文章包含所有单词的个数
def map_with_its_doc_lens(x):
        dic = {}
        l = []
        ll = []
        for i in x:
                dic[i] = dic.get(i,0)+1
        for k,v in dic.items():
                l.append((k,v))
        ll.append(l)
        ll.append(len(x))
        return ll
##这个函数用于正则化,为了使结果对比更加明显
def normalize(x):
        sum = 0
        li = []
        for i in x:
                sum+=i[1]**2
        sum = sum**0.5
        for i in x:
                li.append((i[0],i[1]/sum))
        return li
if __name__ == '__main__':
    # spark的基本配置
    conf = SparkConf().setAppName("tf-idf").setMaster("local")
    sc = SparkContext(conf=conf)
    #创建rdd并进行缓存,缓存的目的是为了防止重复计算
    docs_rdd = sc.parallelize(doc_list).cache()
    #对每篇文章进行计数
    word_tf = docs_rdd.map(lambda x:map_with_its_doc_lens(x)).map(lambda x:[(i[0],i[1]/x[1]) for i in x])
    #计算idf
    word_idf = docs_rdd.map(lambda x:list(set(x)))\
            .flatMap(lambda x:[(i,1) for i in x])\
            .reduceByKey(lambda x,y:x+y).map(lambda x:(x[0],math.log((doc_num+1)/(x[1]+1),2))).collect()
    #idf值转化成字典
    word_idf_dict = dict(word_idf)
    #设置广播变量,一个executor上的所有task共享这个idf字典,减少空间开销
    broadcast_idf_dict = sc.broadcast(word_idf_dict)
    #计算tf*idf
    word_tf_idf = word_tf.map(lambda x:[(i[0],i[1]*broadcast_idf_dict.value[i[0]])for i in x])
    #正则化结果
    word_normalize_result = word_tf_idf.map(lambda x:normalize(x)).collect()
    #排序输出结果
    for i in word_normalize_result:
            print(sorted(i,key=lambda x:x[1]))
    sc.stop()

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值