spark机器学习点击量推荐

通过用户对音乐点击推荐相应的产品
使用分析方法:ROC分析法
ROC分析是从医疗分析领域引入了一种新的分类模型performance评判方法。
算法:AUC
AUC是一种用来度量分类模型好坏的一个标准。
AUC的值就是处于ROC curve下方的那部分面积的大小。通常,AUC的值介于0.5到1.0之间,较大的AUC代表了较好的performance。

用户产品点击列表
这里写图片描述

产品信息表
这里写图片描述

为规范数据建立的中间表
这里写图片描述

此点击推荐系统,没有分出一部分测试,验证测试和结果的误差率
step1:加载

def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
val conf=new SparkConf().setAppName("Recommender").setMaster("local").setExecutorEnv("spark.executor.memory","3072m").setExecutorEnv("SPARK_DRIVER_MEMORY","3072m")
val sc = new SparkContext(conf)
val base = "F:/datafile/lisence/"
val rawUserArtistData = sc.textFile(base + "user_artist_data.txt")//用户产品点击表加载
val rawArtistData = sc.textFile(base + "artist_data.txt")//产品数据表加载
val rawArtistAlias = sc.textFile(base + "artist_alias.txt")//误差名字转换表加载
evaluate(sc, rawUserArtistData,rawArtistData, rawArtistAlias) 
sc.stop()
}

step2:执行

def evaluate(
                sc: SparkContext,
                rawUserArtistData: RDD[String],
                rawArtistData: RDD[String],
                rawArtistAlias: RDD[String]): Unit = {
val bArtistAlias = sc.broadcast(buildArtistAlias(rawArtistAlias))
  //Broadcast(广播)是相对较为常用方法功能,通常使用方式,包括共享配置文件,map数据集,树形数据结构等,为能够更好更快速为TASK任务使用相关变量。
val allData = buildRatings(rawUserArtistData, bArtistAlias)
    //转换格式不正确数据,并构建Rating
val Array(trainData, cvData) = allData.randomSplit(Array(0.9, 0.1))
    //数据按比率随机分块,90%用户训练,10%真实数据验证
trainData.cache()
    //缓存训练数据
cvData.cache()
    //缓存真实数据

val allItemIDs = allData.map(_.product).distinct().collect()
val bAllItemIDs = sc.broadcast(allItemIDs)
    //把用户中的产品所有的数据集合存起来

var bestauc=Double.MinValue
var bestModel: Option[MatrixFactorizationModel] = None 
//最好模型
for (rank   <- Array(10,50);
     lambda <- Array(1.0, 0.0001);
     alpha  <- Array(1.0, 40.0)) {
     val model = ALS.trainImplicit(trainData, rank, 10, lambda, alpha) 
     //模型训练
     val auc = areaUnderCurve(cvData, bAllItemIDs, model)
     //求auc
     unpersist(model)
     if(bestauc<auc){
            bestauc=auc
            bestModel=Some(model)
          }
        }

trainData.unpersist()
cvData.unpersist()

val artistByID = buildArtistByID(rawArtistData)

val someUsers = allData.map(_.user).distinct().take(5)//这里取5个用户
val someRecommendations=someUsers.map(userID=>bestModel.get.recommendProducts(userID, 5))//推荐5个产品给用户

someRecommendations.map(
  recs => recs.head.user + " -> " +artistByID.filter { case (id, name) => recs.map(_.product).contains(id) }.values.collect().mkString(", ")
    ).foreach(println)
allData.unpersist()
unpersist(bestModel.get)
  }

step3:auc计算

def areaUnderCurve(
                      positiveData: RDD[Rating],
                      bAllItemIDs: Broadcast[Array[Int]],
                      model: MatrixFactorizationModel) = {

    val positiveUserProducts = positiveData.map(r => (r.user, r.product))
    val positivePredictions = model.predict(positiveUserProducts).groupBy(_.user)
    val negativeUserProducts = positiveUserProducts.groupByKey().mapPartitions {
      userIDAndPosItemIDs => {
      val random = new Random()
      val allItemIDs = bAllItemIDs.value
        userIDAndPosItemIDs.map { case (userID, posItemIDs) =>
        val posItemIDSet = posItemIDs.toSet  
        //此为一个产品序列
        val negative = new ArrayBuffer[Int]()
        var i = 0
          while (i < allItemIDs.size && negative.size < posItemIDSet.size) {
            //按每个产品序列长度遍历
          val itemID = allItemIDs(random.nextInt(allItemIDs.size))
            //随机一个用户列表里面的产品
            if (!posItemIDSet.contains(itemID)) {
              negative += itemID
              //向数组中加入与原来不一样的产品
            }
            i += 1
          }
          negative.map(itemID => (userID, itemID))
        }
      }
    }.flatMap(t => t)
    val negativePredictions = model.predict(negativeUserProducts).groupBy(_.user)
    //对用户和产品进行点击量预测
    positivePredictions.join(negativePredictions).values.map {
      case (positiveRatings, negativeRatings) =>
        var correct = 0L
        var total = 0L
        for (positive <- positiveRatings;
             negative <- negativeRatings) {
          if (positive.rating > negative.rating) {
            correct += 1
          }
          total += 1
        }
        correct.toDouble / total
    }.mean()
    //AUC计算
  }

step4:数据处理

//去除缓存
  def unpersist(model: MatrixFactorizationModel): Unit = {
    model.userFeatures.unpersist()
    model.productFeatures.unpersist()
  }

  //构建Rating
  def buildRatings(
                    rawUserArtistData: RDD[String],  //未转换用户产品信息表
                    bArtistAlias: Broadcast[Map[Int,Int]]) = {
    rawUserArtistData.map { line =>
      val Array(userID, artistID, count) = line.split(' ').map(_.toInt)
      val finalArtistID = bArtistAlias.value.getOrElse(artistID, artistID)
      //如果匹配返回artistID匹配到的对象,没匹配到返回artistID(原来值)
      Rating(userID, finalArtistID, count)
    }
  }

  //产品数据
  def buildArtistByID(rawArtistData: RDD[String]) =
    rawArtistData.flatMap { line =>
      val (id, name) = line.span(_ != '\t')
      if (name.isEmpty) {
        None
      } else {
        try {
          Some((id.toInt, name.trim))
        } catch {
          case e: NumberFormatException => None
        }
      }
    }
  //把产品中不规范的数据建立映射
  def buildArtistAlias(rawArtistAlias: RDD[String]): Map[Int,Int] =
    rawArtistAlias.flatMap { line =>
      val tokens = line.split('\t')
      if (tokens(0).isEmpty) {
        None
      } else {
        Some((tokens(0).toInt, tokens(1).toInt))
      }
    }.collectAsMap()

总结:
1.spark支持机器学习,对于不属于这领域的人学习更加方便了。
2.什么场景用什么算法公式对于初学者很重要。
3.观察evaluate函数,你会发现 推荐系统很简单,最重要在于算法的应用和编写。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值