ALS音樂推薦(上)

  本篇文章的開頭筆者提出一個疑問,何爲數據科學,數據科學是作什麼的?你們帶着這個疑問去讀接下來的這篇音樂推薦的公衆號。html

  從經驗上講,推薦引擎屬於大規模機器學習,在平常購物中你們或許深有體會,好比:你在淘寶上瀏覽了一些商品,或者購買了一些商品,那麼淘寶就會根據你的偏好給你推薦一些其餘相似的商品。然而,相比較其餘機器學習算法,推薦引擎的輸出更加的直觀,有時候的推薦效果讓人吃驚。做爲機器學習開篇文章,本篇文章會系統的介紹基於Audioscrobbler數據集的音樂推薦。ios

數據集介紹算法

  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。微信

推薦算法介紹dom

  因爲所選取的數據集只記錄了用戶和歌曲之間的交互狀況,除了藝術家名字以外沒有其餘信息。所以要找的學習算法不須要用戶和藝術家的屬性信息,這類算法一般被稱爲協同過濾。若是根據兩個用戶的年齡相同來判斷他們可能具備類似的偏好,這不叫協同過濾。相反,根據兩個用戶播放過許多相同歌曲來判斷他們可能都喜歡某首歌,這是協調過濾。機器學習

  本篇所用的算法在數學上稱爲迭代最小二乘,把用戶播放數據當成矩陣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(_ != '\t')

    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('\t')

    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從關注開始
相關文章
相關標籤/搜索