scala实现pageRank梳理+textRank生成文本摘要

本文详细介绍了PageRank算法的原理及其实现过程,并基于此提出了文本摘要提取的TextRank算法。通过对比句子间的相似度,实现了关键词句的提取。使用Spark进行大规模数据处理,展示了算法的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、数据集准备:空格后面网址为前面网页中链接到的url

72519f7a4e57dc16349e8079fc28003217a.jpg

二、思路梳理

d672bc2392965aafe1cc52e95b6e3d1924c.jpg

fbf14180c66d988eecf68f3e26b0e0f1a4d.jpg

一个网页链接了几个url,就相当于给几个url进行的投票,那么它给其他url投票的分数就为:自己的得分/自己链接的url个数----(目前暂时不考虑给每个url投票的权重,默认都为1),所以我们需要按照每个url聚合,将它投票的网页聚合在一起,然后展开聚合后的多个url,每个url的得分就为:投票url/聚合url个数,这样每个url都能得到其他url给他的投票得分,最后按照key值求和就得出各个url被投票得分的总和。再根据修正后的pageRank公式计算出相关得分。

三、代码实现

object pageRank extends App{
  val spark = SparkSession
    .builder
    .appName("SparkPageRank")
    .master("local[*]")
    .getOrCreate()
  val path="file:///C:\\Users\\91BGJK2\\Desktop\\pageRank.txt"
  //val iters = if (args.length > 1) args(1).toInt else 10
  val iters = 10// 迭代10次

  val lines = spark.read.textFile(path).rdd
  //获取每个页面的关联页面----去除重复投票
  val links = lines.map{ s =>
    val parts = s.split("\\s+")
    (parts(0), parts(1))
  }.distinct()
  //按照每个页面聚合自己投票的url
  val link_group=links.groupByKey().cache()
  var ranks: RDD[(String, Double)] = link_group.mapValues(v => 1.0)//给每个页面初始得分都为1

  //迭代计算每个页面的得分值
  for (i <- 1 to iters) {
    val contribs= link_group.join(ranks).flatMap{ case (id,(urls, rank)) =>
      val size = urls.size
      urls.map(url => (url, rank / size))//计算出每个url被投票的得分
    }
    //计算每个url被投票了得多少分---key值聚合
    ranks = contribs.reduceByKey(_ + _).mapValues(0.15 + 0.85 * _)
  }
  ranks.collect().sortWith(_._2>_._2).foreach(urls=>println(urls._1+"==>"+urls._2))
  spark.stop()
}

四、文本摘要提取

本次提取文本摘要主要是通过比较句子间的相似度,类似pageRank中url之前的投票机制,只不过这个是每个句子间都会有交集会产生相似度,因此本次就借鉴pageRank的算法实现筛选出的分最高的句子,作为文本中的keySentence(提取关键词也可以用类似的方法)。

本次采用:spark+jieba+Word2vec实现

2bf4ddb5f85fcbea41bfcdfae8d4ca7f21e.jpg

通过Word2vec得分句子间的向量,利用欧式距离求相似度,构建相邻矩阵(如图)

例:计算第一句的得分:

=1-0.85+0.85*(与第二句的相似度/第二句投给其他句子的相似度之和+与第三句的相似度/第三句投给其他句子的相似度之和)

295d72795e4baebb34f6960c95287375011.jpg

最后通过迭代计算最终得分

代码:(备注,由于本次spark训练的word2vec模型不能加载,所有直接采用简单的计算句子间的相似度算法)

415c38f6509c947d4100cb7c0073ad40646.jpg

Similarity(S1,S2) = s1s2相同词的个数 / ( log(s1的词个数) + log(s2的词个数) ) 

 

object 文本摘要提取textRank extends App{
  val spark = SparkSession
    .builder
    .appName("SparkPageRank")
    .master("local[*]")
    .getOrCreate()
  val path="file:///C:\\Users\\91BGJK2\\Desktop\\人民的名义.txt"
  val text="朝鲜外相今抵新加坡,穿黑西装打紫色领带,将与多国外长会谈。朝鲜外相李勇浩今抵新加坡。朝中社英文版2日的报道称,李勇浩率领朝鲜代表团于当天启程,除了新加坡,他还将访问伊朗。"
  //分句拆词
  val sent:Map[Int, List[String]]=splitSentence(text)
  val metric=createMat(sent)
  for(i<-metric)println(i.mkString(" "))
  val ranks=Array.ofDim[Double](metric.length).map(str=>1.0)
  //循环迭代结算得分
  for(i<-0 until 5){
    val res:Map[Int, Double]=sent.keys.map{ line=>
      val score=pageRank(metric,ranks,line)
      line->score
    }.toMap
    res.foreach(str=>println("句子"+str._1+"=="+str._2))
    //更新第一次循环后的得分
    res.map(str=>ranks.update(str._1,str._2))
  }
  

  //使用pageRand算法计算句子排名----计算单个句子的得分
  def pageRank(board:Array[Array[Double]],ranks:Array[Double],num:Int): Double ={
      val len=board.length
      val d = 0.85
      var added_score = 0.0
      for(j<-0 until len){
        var fraction = 0.0
        var denominator:Double = 0.0
        // 先计算分子
        fraction= board(j)(num) * ranks(j)
        // 计算分母
        for(k<-0 until len){
          denominator = denominator + board(j)(k)
        }
        added_score += fraction / denominator
      }
    val weighted_score = (1 - d) + d * added_score
    return weighted_score
  }

  //构建句子间的相邻矩阵
  def createMat(document:Map[Int, List[String]]): Array[Array[Double]] ={
    val num = document.size
    // 初始化表
    val board=Array.ofDim[Double](num,num)
    for(i<-0 until  num){
      for(j<-0 until num){
        if(i!=j){
          board(i)(j) = similar_cal(document.get(i).get, document.get(j).get)._2
        }
      }
    }
    return board
  }
  //句子间的相似度计算:共同词个数/log(len1)+log(len2)
  def similar_cal(sent1:List[String],sent2:List[String]): ((String, String), Double) ={
      val same_word=sent1.intersect(sent2)
      val sim=same_word.size/(math.log(sent1.size)+math.log(sent2.size))
      (sent1.toString(),sent2.toString())->sim
  }

  //中文分词
  def cutWord(sentense:String): List[String] ={
    val jieba = new JiebaSegmenter
    val sent_split:List[String]= jieba.sentenceProcess(sentense).asScala.toList.filterNot(str=>str.matches(",|“|”|:|、"))
    return sent_split
  }
  //拆分句子
  def  splitSentence(document:String ): Map[Int, List[String]] ={
      val pattern="(。|!|?|\\.|\\!|\\?)".r
      val res=pattern.split(document).toList.zipWithIndex.map(str=>str._2->cutWord(str._1)).toMap
      return res
  }
  //两个list中的交集
  def getUnio(): Unit ={
    val list1=List("方向","既明","举措","频出")
    val list2=List("方向","既明","好","频出")
    val res=list1.intersect(list2)
    res.foreach(println(_))
  }
  //训练词向量
  def getWord2Vec(): Unit ={
    val jieba = new JiebaSegmenter
    val sc=spark.sparkContext
    val input= sc.textFile("file:///C:\\Users\\91BGJK2\\Desktop\\人民的名义.txt").map(line => cutWord(line).toSeq)
    val word2vec = new Word2Vec()
    val model = word2vec.fit(input)
    val vectors:Map[String, Array[Float]] = model.getVectors
    vectors.foreach(str=>println(str._1+"==>"+str._2.toString))
    //println(model.transform("平"))
   // vectors.foreach(println(_))
    //model.save(sc,"file:///C:\\U'sers\\91BGJK2\\Desktop\\word.model")
    spark.stop()
  }
}

 

参考博客:

https://blog.youkuaiyun.com/oxuzhenyi/article/details/54981372

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值