美文网首页
基于内容的推荐

基于内容的推荐

作者: kang_james | 来源:发表于2019-06-13 23:47 被阅读0次

    首先来看一个例子:
    我们已经知道
    1)、用户u1喜欢的电影是A,B,C
    2)、用户u2喜欢的电影是A,C,E,F
    3)、用户u3喜欢的电影B,D
    我们需要解决的问题是:决定对u1是不是应该推荐F这部电影
    基于内容的做法:要分析F的特征和u1所喜欢的A,B,C的特征,需要知道的信息是A(战争片),B(战争片),C(剧情片),如果F(战争片),那么F很大程度上可以推荐给u1,这是基于内容的做法,你需要对item进行特征建立和建模,利用模型给F打分

    引入item属性的content Based推荐

    image.png

    1)对item内容进行分析(一般对item描述性信息和标签等内容进行分析),对item内容进行中文分词,得到item_id、word以及score
    2)、对上一步得到的item_id、word、score建立一个倒排索引即word [item_id1:score,item_id2:score,.....],以word为key,进行groupby,然后对score进行排序
    3)、对历史浏览数据进行特征处理和建模
    4)、然后对推荐结果进行重新打分排序

    优缺点:

    优点:
    1、提升推荐结果的相关性
    2、结果可解释
    3、推荐结果容易被用户感知
    缺点:
    1、无个性化
    2、依赖对item的深度分析

    引入user属性的Content Based推荐

    image.png

    1)对item内容进行分析(一般对item描述性信息和标签等内容进行分析),对item内容进行中文分词,得到item_id、word以及score
    2)、对上一步得到的item_id、word、score建立一个倒排索引即word [item_id1:score,item_id2:score,.....],以word为key,进行groupby,然后对score进行排序
    3)、用户行为数据进行分析,对用户兴趣建模
    4)、然后对推荐结果进行重新打分排序

    优缺点:

    优点:
    1、用户模型刻画了用户兴趣需求
    2、推荐形式多样,具有个性化
    3、结果可解释
    缺点:
    推荐精度低
    马太效应
    用户行为稀疏导致覆盖率低

    代码如下:

    package cb
    
    import com.huaban.analysis.jieba.{JiebaSegmenter, SegToken}
    import com.huaban.analysis.jieba.JiebaSegmenter.SegMode
    import org.apache.spark.SparkConf
    import org.apache.spark.ml.feature.StopWordsRemover
    import org.apache.spark.sql.{DataFrame, SparkSession}
    import org.apache.spark.sql.functions._
    import scala.util.matching.Regex
    
    object CBTest {
    
      case class Music(music_id:String, music_content:String)
      case class StopWords(stopword:String)
      case class IdfWords(word:String,idf:String)
    
      def main(args: Array[String]): Unit = {
        val conf = new SparkConf()
          .registerKryoClasses(Array(classOf[JiebaSegmenter]))
        val spark = SparkSession
          .builder()
          .appName("cb")
          .master("local")
          .config("spark.sql.warehouse.dir","D:\\hadoop\\sparkTest\\data\\music_meta.txt")
                          .config("spark.sql.warehouse.dir","D:\\hadoop\\sparkTest\\data\\stopwords.txt")
          .config("spark.sql.warehouse.dir","D:\\hadoop\\sparkTest\\data\\idf.txt")
          .config(conf)
          .getOrCreate()
        
        import spark.implicits._
        val music_data = spark.sparkContext.textFile("D:\\hadoop\\sparkTest\\data\\music_meta.txt")
        val stop_word = spark.sparkContext.textFile("D:\\hadoop\\sparkTest\\data\\stopwords.txt").collect()
        val word_idf = spark.sparkContext.textFile("D:\\hadoop\\sparkTest\\data\\idf.txt")
    
        val music_df = music_data.map(_.toString.trim.split("\t")).map(music =>Music(music(0).trim, music(1).trim)).toDF("music_id","music_content")
        val word_idf_df = word_idf.map(_.toString.trim.split(" ")).map(line => IdfWords(line(0).trim,line(1).trim)).toDF("word_idf","idf")
    
    
         //定义一个结巴分词的udf
        def jieba_udf(df:DataFrame, colname:String) : DataFrame ={
          val segmenter = new JiebaSegmenter()
          val seg = spark.sparkContext.broadcast(segmenter)
          val seg_udf = udf{music_content:String =>
            val segV = seg.value
            segV.process(music_content.toString,SegMode.INDEX)
              .toArray()
              .map(_.asInstanceOf[SegToken].word)
          }
          df.withColumn("words",seg_udf(col(colname)))
        }
    
        val seg_df = jieba_udf(music_df,"music_content").select("music_id","words")
        seg_df.show(false)
        //去停用词
        val remover = new StopWordsRemover().setStopWords(stop_word).setInputCol("words").setOutputCol("filter_words")
        val filter_seg_df = remover.transform(seg_df).select("music_id","filter_words")
        filter_seg_df.show(false)
    
        val explode_df =  filter_seg_df.selectExpr("music_id","explode(filter_words) as word").where("word <> ' '")
          .select("music_id","word")
        explode_df.show(false)
        val music_id_word_idf = explode_df.join(word_idf_df,explode_df("word")===word_idf_df("word_idf")).drop("word_idf")
        //获取倒排索引,并排序
        val word_group = music_id_word_idf.rdd.map(line => (line(1).toString,(line(0).toString,line(2).toString)))
          .groupByKey().mapValues{x=>
          x.toArray.sortWith((x,y) => x._2 > y._2).slice(0,10)
        }.toDF("word","music_id_array").select("word","music_id_array")
        word_group.show(false)

    相关文章

      网友评论

          本文标题:基于内容的推荐

          本文链接:https://www.haomeiwen.com/subject/jwqefctx.html