基于内容的推荐

2019-06-13  本文已影响0人  kang_james

首先来看一个例子:
我们已经知道
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)
上一篇 下一篇

猜你喜欢

热点阅读