spark機器學習:使用ALS完成商品推薦

你这过氧化氢掺水了發表於2024-11-28

ALS(Alternating Least Squares)是一種廣泛使用的推薦系統演算法,特別用於協同過濾(Collaborative Filtering)任務。在 Apache Spark 中,ALS 被實現為 org.apache.spark.ml.recommendation.ALS 類,適用於大規模資料集,並能夠有效地處理稀疏矩陣,常用於推薦引擎。

目錄
  • ALS 演算法的基本思想
  • 在Spark 中使用 ALS
  • ALS實踐練習


ALS 演算法的基本思想

ALS 的主要思想是:

  1. 分解矩陣:ALS 透過將使用者-專案評分矩陣分解為兩個低秩矩陣——使用者特徵矩陣和專案特徵矩陣。這使得可以透過使用者和專案之間的特徵相似度來預測評分。

  2. 交替最佳化:該演算法交替地固定使用者特徵矩陣和專案特徵矩陣,並透過最小化損失函式(通常是均方誤差)來最佳化這兩個矩陣。具體的最佳化步驟是:

    • 在固定專案特徵矩陣的情況下,最佳化使用者特徵矩陣。
    • 然後在固定使用者特徵矩陣的情況下,最佳化專案特徵矩陣。
    • 重複以上步驟直到收斂。

在Spark 中使用 ALS

在 Spark 中,ALS 提供了一種簡單而高效的方式來構建推薦模型。以下是使用 Spark 中的 ALS 的基本步驟:

  1. 匯入必要的庫

    import org.apache.spark.ml.recommendation.ALS
    import org.apache.spark.sql.SparkSession
    
  2. 建立 Spark 會話

    val spark = SparkSession.builder()
        .appName("ALSExample")
        .getOrCreate()
    
  3. 準備資料

    資料應包含使用者 ID、專案 ID 和評分,通常以 DataFrame 格式儲存。

    val ratings = Seq(
        (0, 0, 4), 
        (0, 1, 2),
        (1, 0, 5), 
        (1, 1, 1)
    ).toDF("userId", "itemId", "rating")
    
  4. 構建 ALS 模型

    val als = new ALS()
        .setUserCol("userId")
        .setItemCol("itemId")
        .setRatingCol("rating")
        .setColdStartStrategy("drop") // 保證對待沒有評分的預測結果的處理
        .setRank(10) // 設定特徵向量的維度
        .setMaxIter(10) // 最大迭代次數
    
    val model = als.fit(ratings)
    
  5. 生成推薦

    可以使用模型生成使用者和專案的推薦。

    val userRecs = model.recommendForAllUsers(5) // 為所有使用者推薦 5 個專案
    val itemRecs = model.recommendForAllItems(5) // 為所有專案推薦 5 個使用者
    

ALS實踐練習

資料展示:
三列資料分別為使用者 ID、物品 ID 和評分

1,1,5.0
1,2,1.0
1,3,5.0
1,4,1.0
2,1,5.0
2,2,1.0
2,3,5.0
2,4,1.0
3,1,1.0
3,2,5.0
3,3,1.0
3,4,5.0
4,1,1.0
4,2,5.0
4,3,1.0
4,4,5.0

在hdfs檔案系統,建立目錄,名為mymllib5,並將linux上的myrating檔案資料,上傳到hdfs

hadoop fs -mkdir /mymllib5
hadoop fs -put /myrating /mymllib5


啟動spark-shell

spark-shell

為了執行協同過濾操作,需要首先匯入執行統計所依賴的包

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.mllib.recommendation.ALS
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel
import org.apache.spark.mllib.recommendation.Rating

讀取hdfs上的myrating文字檔案

val data = sc.textFile("hdfs://192.168.88.161:8020/mymllib5/myrating")


把資料轉化成rating型別,即[Int, Int, Double]的RDD;

val ratings = data.map(_.split(",") match {  
	case Array(user, item, rate) =>  
	Rating(user.toInt, item.toInt, rate.toDouble)  
	})  

檢查一下資料格式是否符合要求

ratings.foreach{x => println(x)}


劃分訓練集和測試集,比例分別是0.8和0.2。

val splits = ratings.randomSplit(Array(0.8, 0.2))

將80%作為訓練資料集

val training = splits(0)

將20%作為測試資料集

val test = splits(1)


指定引數值,然後使用ALS訓練資料建立推薦模型:

val rank = 10
val numIterations = 10
val model = ALS.train(training, rank, numIterations, 0.01)


使用訓練好的推薦模型對使用者商品進行預測評分,得到預測評分的資料集

val testUsersProducts = test.map { case Rating(user, product, rate) => (user, product) }

使用訓練好的推薦模型對使用者商品進行預測評分,得到預測評分的資料集:

val predictions =
    model.predict(testUsersProducts).map { case Rating(user, product, rate) =>((user, product), rate)
	}


將真實評分資料集與預測評分資料集進行合併。這裡,Join操作類似於SQL的inner join操作,返回結果是前面和後面集合中配對成功的,過濾掉關聯不上的。

val ratesAndPreds = test.map { case Rating(user, product, rate) => ((user, product), rate) }.join(predictions)

我們把結果輸出,對比一下真實結果與預測結果:

ratesAndPreds.foreach(println)

檢視輸出效果:

比如,第一條結果記錄((1,4),(1.0,2.0765385175171436))中,(1,4)分別表示1號使用者和4號商品,而1.0是實際的估計分值,2.0765385175171436是經過推薦的預測分值。


當然,我們也可以針對於某一個人進行預測,對比結果。

val result = model.recommendProducts(2, 1)
result.foreach(println)


然後計算均方差,這裡的r1就是真實結果,r2就是預測結果:

val MSE = ratesAndPreds.map { case ((user, product), (r1, r2)) => 
	    val err = (r1 - r2) 
	    err * err 
	}.mean() 

把輸出結果列印出來:

println("Mean Squared Error = " + MSE)

輸出效果:
看到打分的均方差值為1.44左右


相關文章