• ALS音乐推荐(上)


      本篇文章的开头笔者提出一个疑问,何为数据科学,数据科学是做什么的?大家带着这个疑问去读接下来的这篇音乐推荐的公众号。

      从经验上讲,推荐引擎属于大规模机器学习,在日常购物中大家或许深有体会,比如:你在淘宝上浏览了一些商品,或者购买了一些商品,那么淘宝就会根据你的偏好给你推荐一些其他类似的商品。然而,相比较其他机器学习算法,推荐引擎的输出更加的直观,有时候的推荐效果让人吃惊。作为机器学习开篇文章,本篇文章会系统的介绍基于Audioscrobbler数据集的音乐推荐。

    数据集介绍

      Audioscrobbler数据集是一个公开发布的数据集,读者可以在(http://www-etud.iro.umontreal.ca/~bergstj/audioscrobbler_data.html)网站获取。数据集主要有三部分组成,user_artist_data.txt文件是主要的数据集文件记录了约2420条用户id、艺术家id以及用户收听艺术家歌曲的次数数据,包含141000个用户和160万个艺术家;artist_data.txt文件记录了艺术家id和对应的名字;artist_alias.txt记录了艺术家id和对应的别称id。

    推荐算法介绍

      由于所选取的数据集只记录了用户和歌曲之间的交互情况,除了艺术家名字之外没有其他信息。因此要找的学习算法不需要用户和艺术家的属性信息,这类算法通常被称为协同过滤。如果根据两个用户的年龄相同来判断他们可能具有相似的偏好,这不叫协同过滤。相反,根据两个用户播放过许多相同歌曲来判断他们可能都喜欢某首歌,这是协调过滤。

      本篇所用的算法在数学上称为迭代最小二乘,把用户播放数据当成矩阵A,矩阵低i行第j列上的元素的值,代表用户i播放艺术家j的音乐。矩阵A是稀疏的,绝大多数元素是0,算法将A分解成两个小矩阵X和Y,既A=XYT,X代表用户特征矩阵,Y代表特征艺术家矩阵。两个矩阵的乘积当做用户-艺术家关系矩阵的估计。可以通过下边一组图直观的反映:

      现在假如有5个听众,音乐有5首,那么A是一个5*5的矩阵,假如评分如下:

    图2.1 用户订阅矩阵

      假如d是三个属性,那么X的矩阵如下:

    图2.2 用户-特征矩阵

      Y的矩阵如下:

    图2.3 特征-电影矩阵

      实际的求解过程中通常先随机的固定矩阵Y,则,为提高计算效率,通常采用并行计算X的每一行,既。得到X之后,再反求出Y,不断的交替迭代,最终使得XYT与A的平方误差小于指定阈值,停止迭代,得到最终的X(代表用户特征矩阵)和Y矩阵(代表特征艺术家矩阵)。在根据最终X和Y矩阵结果,向用户进行推荐。

    ALS的Spark实现

      Spark MLlib的ALS算法实现有点缺陷,要求用户和产品的ID必须是数值型,并且是32位非负整数。在计算之前应该首先检验一下数据量。

    1)数据预处理

      过滤无效的用户艺术家ID和名字行,将格式不正确的数据行剔除掉。

    def buildArtistByID(rawArtistData: Dataset[String]): DataFrame = {
    
      rawArtistData.flatMap { line =>
    
        val (id, name) = line.span(_ != '	')
    
        if (name.isEmpty) {
    
          None
    
        } else {
    
          try {
    
            Some((id.toInt, name.trim))
    
          } catch {
    
            case _: NumberFormatException => None
    
          }
    
        }
    
      }.toDF("id", "name")
    
    }
    

      过滤艺术家id和对应的别名id,将格式拼写错误的行剔除掉。

    def buildArtistAlias(rawArtistAlias: Dataset[String]): Map[Int,Int] = {
    
      rawArtistAlias.flatMap { line =>
    
        val Array(artist, alias) = line.split('	')
    
        if (artist.isEmpty) {
    
          None
    
        } else {
    
          Some((artist.toInt, alias.toInt))
    
        }
    
      }.collect().toMap
    
    }
    

      将数据转换成Rating对象,Rating对象是ALS算法对“用户-产品-值”的抽象。

    def buildCounts(
    
        rawUserArtistData: Dataset[String],
    
        bArtistAlias: Broadcast[Map[Int,Int]]): DataFrame = {
    
      rawUserArtistData.map { line =>
    
        val Array(userID, artistID, count) = line.split(' ').map(_.toInt)
    
        val finalArtistID = bArtistAlias.value.getOrElse(artistID, artistID)
    
        (userID, finalArtistID, count)
    
      }.toDF("user", "artist", "count")
    
    }
    

    2)模型构建

    def model(
    
        rawUserArtistData: Dataset[String],
    
        rawArtistData: Dataset[String],
    
        rawArtistAlias: Dataset[String]): Unit = {
    
      val bArtistAlias = spark.sparkContext.broadcast(buildArtistAlias(rawArtistAlias))  //艺术家别名数据
    
      val trainData = buildCounts(rawUserArtistData, bArtistAlias).cache() //将数据转换成需要的格式
    
      val model = new ALS().
    
        setSeed(Random.nextLong()).
    
        setImplicitPrefs(true).
    
        setRank(10).
    
        setRegParam(0.01).
    
        setAlpha(1.0).
    
        setMaxIter(5).
    
        setUserCol("user").
    
        setItemCol("artist").
    
        setRatingCol("count").
    
        setPredictionCol("prediction").
    
        fit(trainData)
    
      trainData.unpersist()
    
      model.userFactors.select("features").show(truncate = false)
    
      val userID = 2093760
    
      val existingArtistIDs = trainData.
    
        filter($"user" === userID).
    
        select("artist").as[Int].collect()
    
      val artistByID = buildArtistByID(rawArtistData)
    
      artistByID.filter($"id" isin (existingArtistIDs:_*)).show()
    
      val topRecommendations = makeRecommendations(model, userID, 5)
    
      topRecommendations.show()
    
      val recommendedArtistIDs = topRecommendations.select("artist").as[Int].collect()
    
      artistByID.filter($"id" isin (recommendedArtistIDs:_*)).show()
    
      model.userFactors.unpersist()
    
      model.itemFactors.unpersist()
    
    }
    

      本篇文章主要对ALS音乐推荐进行简单的介绍,下一篇会对模型的参数,以及模型的推荐效果进行评估,并且会对推荐结果进行优化。

     备注:如果文中排版出现错乱,请点击https://mp.weixin.qq.com/s/aqF38rDQdT35YrLAyLm-nA

    更多精彩内容,欢迎扫码关注以下微信公众号:大数据技术宅。大数据、AI从关注开始

  • 相关阅读:
    hdu 1443 Joseph 约瑟夫环
    hdu 1568 Fibonacci 对数。。
    UILineBreakMode
    Android RelativeLayout 动态添加组件
    iOS 让view触发点击事件
    读取plist文件数据
    [转]Android获取SD卡视频音频文件
    ubuntu下vim修复
    DMO(DirectX Media Object)的工程创建过程及其调用方式
    《Windows程序设计》笔记 —— Chapter One
  • 原文地址:https://www.cnblogs.com/followees/p/8854406.html
Copyright © 2020-2023  润新知