博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
协同过滤(ALS)
阅读量:5870 次
发布时间:2019-06-19

本文共 4461 字,大约阅读时间需要 14 分钟。

hot3.png

Spark ALS算法进行矩阵分解,U * V = Q

如果数据不是运行在集群上,而是运行在本地,为了保证内存充足,在启动spark-shell时需要指定参数--driver-memory 6g

    1. 数据集

艺术家点播数据集:

用户和艺术家的关系是通过其他行动隐含提现出来的,例如播放歌曲或专辑,而不是通过显式的评分或者点赞得到的。这被称为隐式反馈数据。现在的家用电视点播也是这样,用户一般不会主动评分。

数据集下载地址是http://www.iro.umontreal.ca/~lisa/datasets/profiledata_06-May-2005.tar.gz

    1. 数据处理

Spark MLibALS算法实现有一个小缺点:它要求用户和产品的ID必须是数值型,并且是32位非负整数,这意味着大于Integer.MAX_VALUE2147483647)的ID是非法的。我们首先看看数据集是否满足要求:

scala> val rawUserArtistData = sc.textFile("D:/Workspace/AnalysisWithSpark/src/main/java/advanced/chapter3/profiledata_06-May-2005/user_artist_data.txt")

rawUserArtistData: org.apache.spark.rdd.RDD[String] = D:/Workspace/AnalysisWithSpark/src/main/java/advanced/chapter3/profiledata_06-May-2005/user_artist_data.txt MapPartitionsRDD[1] at textFile at <console>:27

 

scala> rawUserArtistData.map(_.split(' ')(0).toDouble).stats()

res0: org.apache.spark.util.StatCounter = (count: 24296858, mean: 1947573.265353, stdev: 496000.544975, max: 2443548.000000, min: 90.000000)

 

scala> rawUserArtistData.map(_.split(' ')(1).toDouble).stats()

res1: org.apache.spark.util.StatCounter = (count: 24296858, mean: 1718704.093757, stdev: 2539389.040171, max: 10794401.000000, min: 1.000000)

过滤数据

val rawArtistData = sc.textFile("hdfs:///user/ds/artist_data.txt")

val artistByID = 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

        }

    }

}

 

 

    1. 训练算法

首先将数据转换成Rating

import org.apache.spark.mllib.recommendation._

val bArtistAlias = sc.broadcast(artistAlias)

val trainData = rawUserArtistData.map { line =>

    val Array(userID, artistID, count) = line.split(' ').map(_.toInt)

    val finalArtistID =

    bArtistAlias.value.getOrElse(artistID, artistID)

    Rating(userID, finalArtistID, count)

}.cache()

 

val model = ALS.trainImplicit(trainData, 10, 5, 0.01, 1.0)

//查看特征变量:

model.userFeatures.mapValues(_.mkString(", ")).first()

 

//我们可以对此用户做出5个推荐:

val recommendations = model.recommendProducts(2093760, 5)

recommendations.foreach(println)

 

    1. 选择超参数

计算AUC这部分代码没有试。AUC(Area Under ROC Curve)ROC(Receiver Operating Characteristic,受试者工作特征)线,它源于二战中用于敌机检测的雷达信号分析技术。在非均等代价下,ROC曲线不能直接反映出学习器的期望总体代价,而代价曲线则可达到该目的。

机器学习常涉及两类参数:一类是算法的参数,亦称超参数,数目常在10以内;另一类是模型的参数,数目可能很多。前者通常是由人工设定多个参数候选值后产生模型,后者则是通过学习来产生多个候选模型。

ALS.trainImplicit()的参数包括以下几个:

rank

  模型的潜在因素的个数,即用户-特征产品-特征矩阵的列数;一般来说,它也是矩阵的阶。

iterations

  矩阵分解迭代的次数;迭代的次数越多,花费的时间越长,但分解的结果可能会更好。
lambda
  标准的过拟合参数;值越大越不容易产生过拟合,但值太大会降低分解的准确度。lambda取较大的值看起来结果要稍微好一些。
alpha
  控制矩阵分解时,被观察到的用户-产品交互相对没被观察到的交互的权重。40是最初ALS论文的默认值,这说明了模型在强调用户听过什么时的表现要比强调用户没听过什么时要好。

 

    1. 应用(产生推荐)

val someUsers = allData.map(_.user).distinct().take(100)

val someRecommendations =

    someUsers.map(userID => model.recommendProducts(userID, 5))

someRecommendations.map(

    recs => recs.head.user + " -> " + recs.map(_.product).mkString(", ")

).foreach(println)

 

    1. Rating数据代码

def run(filename: String) {

    println("mlALS is running!")

    val data = getData(filename)

    println(s"dataLen:${

data.count}")

 

    val als = new ALS()

      .setMaxIter(5)

      .setRegParam(0.01)

      .setUserCol("newUserId")

      .setItemCol("newMovieId")

      .setRatingCol("newRating");

 

    val split = data.randomSplit(Array(0.8, 0.2))

    val model = als.fit(split(0));

    println(s"userCol name:${

model.getUserCol}")

 

    val predictions = model.transform(split(1))

    val evaluator = new RegressionEvaluator()

      .setMetricName("rmse")

      .setLabelCol("newRating")

      .setPredictionCol("prediction")

    val rmse = evaluator.evaluate(predictions)

   

    println(s"Root-mean-square error = $rmse")

   

    val userCommdmodel.recommendForAllUsers(10)

    userCommd.show()

  }

 

  def getData(filename: String) :Dataset[Row] = {

    val sqlContext = new SQLContext(sc.sparkContext)

    val df = sqlContext.load("com.databricks.spark.csv", Map("path" -> filename, "header" -> "true"))

    df.columns.map(col => println(s"col:${col}"))

   

    val newdf = df.select(df.col("userId").cast(IntegerType).as("newUserId"),

        df.col("movieId").cast(IntegerType).as("newMovieId"),

        df.col("rating").cast(DoubleType).as("newRating"),

        df.col("timestamp").cast(LongType).as("newTimeStamp"))

   

    newdf

  }

 

    1. 数据正则化

 

val dataFrame = sqlContext.read.format("libsvm").load("data/libsvm.txt")

 

    // L1正则化

    val normalizer = new Normalizer().setInputCol("features").setOutputCol("normFeatures")

      // 设置 L1正则化

      .setP(1.0)

    // 正则化转换

val l1NormData = normalizer.transform(dataFrame)

  // L2正则化

     val l2InfNormData = normalizer.transform(dataFrame, normalizer.p -> 2)

    l2InfNormData.foreach(println)

转载于:https://my.oschina.net/u/778683/blog/1831259

你可能感兴趣的文章
用Lucene4.5对中文文本建立索引
查看>>
第五周学习进度表
查看>>
Python-面向对象进阶
查看>>
访问hbase的内部大致流程
查看>>
Elasticsearch如何做到亿级数据查询毫秒级返回?
查看>>
【零基础学习iOS开发】【01-前言】01-开篇
查看>>
当node升级后导致webpack打包出错,node-saas出问题的解决办法
查看>>
linux 常用指令
查看>>
Mysql框架---HMySql
查看>>
Yii在nginx下多目录rewrite
查看>>
关于windows服务器配置
查看>>
android studio 编译加速
查看>>
Mac iphone 使用 如何修改apple 用户名 XXX的mac Mac 与iphone如何连接 传递文件 为iphone增加铃声 iphone铃声的制作---城...
查看>>
AUTOSAR的前期开源实现Arctic Core
查看>>
Disruptor简单应用
查看>>
抽象类与接口对比
查看>>
tarjan算法
查看>>
GreenPlum锁表处理
查看>>
myeclipse 常用快捷键总结
查看>>
栈和堆的区别【个人总结】
查看>>