pyspark-推薦系統(tǒng)-RecommenderSystem

內(nèi)容摘入自<<Python大數(shù)據(jù)分析從入門到精通>>

附書源碼下載地址

更多信息https://blue-shadow.top/

推薦系統(tǒng)

自動(dòng)推薦內(nèi)容或產(chǎn)品以個(gè)性化的方式向適當(dāng)?shù)挠脩籼峁?以增強(qiáng)整體體驗(yàn)。推薦系統(tǒng)在術(shù)語(yǔ)上非常強(qiáng)大使用海量的數(shù)據(jù),學(xué)會(huì)理解偏好。

對(duì)于PySpark中的“推薦系統(tǒng)”模塊 pyspark.ml.recommendation module
官方文檔鏈接:api/python/pyspark.ml.html#module-pyspark.ml.recommendation

spark 推薦系統(tǒng)的ALS 算法

  • 交替最小平方 (ALS) 矩陣分解:
    ALS 嘗試將評(píng)級(jí)矩陣 R 估計(jì)為兩個(gè)較低級(jí)別矩陣(X 和 Y,即 X = Yt = R)的乘積。一般方法是迭代。在每次迭代期間,一個(gè)因子矩陣保持不變,而另一個(gè)因子矩陣使用最小二乘求解。然后,在求解另一個(gè)因子矩陣時(shí),新求解的因子矩陣保持不變。
  • 現(xiàn)實(shí)場(chǎng)景到推薦系統(tǒng)模型的轉(zhuǎn)換 ; 構(gòu)建模型 中的轉(zhuǎn)換關(guān)系

    • 劃分出推薦系統(tǒng)中參與的對(duì)象,如在線購(gòu)物網(wǎng)站中,參與的主要對(duì)象是購(gòu)物者和相關(guān)的商品。
    • 將這些對(duì)象的按維度屬性進(jìn)行劃分,通過這些維度屬性可以有效的表示這個(gè)對(duì)象。如購(gòu)物者可以通過 年齡,性別,所住城市等這些屬性進(jìn)行表示。
    • 將對(duì)象通過對(duì)應(yīng)的屬性維度構(gòu)建好后。假設(shè)每個(gè)對(duì)象可以通過一個(gè)函數(shù)表示,如: ax1 + bx2 + cx3 + dx4 = y 。為每個(gè)對(duì)象,依據(jù)分配的屬性維度個(gè)數(shù),構(gòu)建有相同元的函數(shù)。
    • 通過不同對(duì)象個(gè)體的屬性維度值構(gòu)建矩陣,構(gòu)建好不同對(duì)象的矩陣后,進(jìn)行矩陣相乘。得到的新矩陣可以認(rèn)為是每個(gè)購(gòu)物者對(duì)相關(guān)物品的關(guān)聯(lián)程度。
    • 由于對(duì)象的函數(shù)表示,是通過假設(shè)的,所以需要獲取最優(yōu)函數(shù)的辦法,即通過使用最小二乘法來獲取最佳函數(shù)。
  • 關(guān)于最小二乘法:
    它通過最小化誤差的平方和尋找數(shù)據(jù)的最佳函數(shù)匹配。利用最小二乘法可以簡(jiǎn)便地求得未知的數(shù)據(jù),并使得這些求得的數(shù)據(jù)與實(shí)際數(shù)據(jù)之間誤差的平方和為最小。
    最小二乘法還可用于曲線擬合。其他一些優(yōu)化問題也可通過最小化能量或最大化熵用最小二乘法來表達(dá)。

    通俗的說:在平面(也可再高維度空間種)上有若干點(diǎn),需要使用一個(gè)函數(shù)來表示這些點(diǎn);如何確定這個(gè)函數(shù)是最優(yōu)的;通過在坐標(biāo)系上,每個(gè)點(diǎn)到這個(gè)函數(shù)對(duì)應(yīng)的圖形的距離的和最小,
    由于擬合函數(shù)可以有很多種,但是求兩點(diǎn)的具體方法:坐標(biāo)值差的平方的和,后再開方。 把這些值都加起來后求最小情況,就是最小二乘法。

使用最小二乘法的,不同擬合曲線:

不同函數(shù)的擬合曲線

推薦系統(tǒng)的分類

基于內(nèi)容推薦
基于內(nèi)容的推薦(Content-based Recommendation)是信息過濾技術(shù)的延續(xù)與發(fā)展,它是建立在項(xiàng)目的內(nèi)容信息上作出推薦的,而不需要依據(jù)用戶對(duì)項(xiàng)目的評(píng)價(jià)意見,更多地需要用機(jī) 器學(xué)習(xí)的方法從關(guān)于內(nèi)容的特征描述的事例中得到用戶的興趣資料

協(xié)同過濾推薦
協(xié)同過濾推薦(Collaborative Filtering Recommendation)技術(shù)是推薦系統(tǒng)中應(yīng)用最早和最為成功的技術(shù)之一。它一般采用最近鄰技術(shù),利用用戶的歷史喜好信息計(jì)算用戶之間的距離,然后 利用目標(biāo)用戶的最近鄰居用戶對(duì)商品評(píng)價(jià)的加權(quán)評(píng)價(jià)值來預(yù)測(cè)目標(biāo)用戶對(duì)特定商品的喜好程度,系統(tǒng)從而根據(jù)這一喜好程度來對(duì)目標(biāo)用戶進(jìn)行推薦

基于關(guān)聯(lián)規(guī)則推薦
基于關(guān)聯(lián)規(guī)則的推薦(Association Rule-based Recommendation)是以關(guān)聯(lián)規(guī)則為基礎(chǔ),把已購(gòu)商品作為規(guī)則頭,規(guī)則體為推薦對(duì)象。關(guān)聯(lián)規(guī)則挖掘可以發(fā)現(xiàn)不同商品在銷售過程中的相關(guān)性,在零 售業(yè)中已經(jīng)得到了成功的應(yīng)用

基于知識(shí)推薦
基于知識(shí)的推薦(Knowledge-based Recommendation)在某種程度是可以看成是一種推理(Inference)技術(shù),它不是建立在用戶需要和偏好基礎(chǔ)上推薦的?;谥R(shí)的方法因 它們所用的功能知識(shí)不同而有明顯區(qū)別

組合推薦
由于各種推薦方法都有優(yōu)缺點(diǎn),所以在實(shí)際中,組合推薦(Hybrid Recommendation)經(jīng)常被采用。研究和應(yīng)用最多的是內(nèi)容推薦和協(xié)同過濾推薦的組合。最簡(jiǎn)單的做法就是分別用基于內(nèi)容的方法和協(xié)同過濾推薦方法 去產(chǎn)生一個(gè)推薦預(yù)測(cè)結(jié)果,然后用某方法組合其結(jié)果

基于效用推薦
基于效用的推薦(Utility-based Recommendation)是建立在對(duì)用戶使用項(xiàng)目的效用情況上計(jì)算的,其核心問題是怎么樣為每一個(gè)用戶去創(chuàng)建一個(gè)效用函數(shù),因此,用戶資料模型很大 程度上是由系統(tǒng)所采用的效用函數(shù)決定的。基于效用推薦的好處是它能把非產(chǎn)品的屬性,如提供商的可靠性(Vendor Reliability)和產(chǎn)品的可得性(Product Availability)等考慮到效用計(jì)算中

wiki上關(guān)于推薦系統(tǒng)

示例代碼

  • 測(cè)試數(shù)據(jù)-用戶電影評(píng)分MovieLens, MovieLens 是歷史最悠久的推薦系統(tǒng)。它由美國(guó) Minnesota 大學(xué)計(jì)算機(jī)科學(xué)與工程學(xué)院的 GroupLens 項(xiàng)目組創(chuàng)辦,是一個(gè)非商業(yè)性質(zhì)的、以研究為目的的實(shí)驗(yàn)性站點(diǎn)。MovieLens 主要使用 Collaborative Filtering 和 Association Rules 相結(jié)合的技術(shù),向用戶推薦他們感興趣的電影

MovieLens https://grouplens.org/datasets/movielens/

完整數(shù)據(jù)下載
數(shù)據(jù)樣例下載

在成功獲取數(shù)據(jù),對(duì)文件內(nèi)容進(jìn)行說明介紹:

  • ratings.csv - 電影評(píng)分?jǐn)?shù)據(jù)集
    userId,movieId,rating,timestamp 為其數(shù)據(jù)列:表示每個(gè)用戶對(duì)每部電影在什么時(shí)候的評(píng)分。

  • movies.csv - 對(duì)電影的分類數(shù)據(jù)集
    movieId,title,genres 為其數(shù)據(jù)列:表示了每部電影的名字和分類

  • tags.csv - 標(biāo)簽文件
    userId,movieId,tag,timestamp 為其數(shù)據(jù)列:表示每個(gè)用戶對(duì)電影的分類

  • links.csv -
    movieId,imdbId,tmdbId 為其數(shù)據(jù)列: 每個(gè)電影的 imdb(網(wǎng)路電影資料庫(kù)),tmdb(電影數(shù)據(jù)庫(kù))的關(guān)聯(lián)編號(hào)

from pyspark.sql import SparkSession 
spark=SparkSession.builder.appName('rs').getOrCreate()

from pyspark.sql.functions import *

print('-------------查看數(shù)據(jù)情況,檢測(cè)數(shù)據(jù)質(zhì)量和相關(guān)的特征。即相對(duì)數(shù)據(jù)有一定的認(rèn)識(shí),對(duì)后續(xù)進(jìn)行訓(xùn)練做準(zhǔn)備--------------------')

df_ratings=spark.read.csv('ml-latest-small/ratings.csv',inferSchema=True,header=True)   # 讀取電影評(píng)分?jǐn)?shù)據(jù)
df_ratings.createOrReplaceTempView("ratings")       # 構(gòu)建臨時(shí)表評(píng)分表
df_movie=spark.read.csv('ml-latest-small/movies.csv',inferSchema=True,header=True)      # 讀取電影數(shù)據(jù)
df_movie.createOrReplaceTempView("movies")          # 構(gòu)建臨時(shí)電影表,這兩張表通過sql關(guān)聯(lián),得到具體電影的評(píng)分信息

df_details = spark.sql("SELECT ratings.userId , ratings.movieId , movies.title , movies.genres , ratings.rating  FROM ratings   \
          LEFT JOIN movies ON ratings.movieId = movies.movieId ")       # 兩表關(guān)聯(lián),獲取具體的信息
          
df_details.select('userId','title','rating').where('rating=4').show(10)

print((df_details.count(),len(df_details.columns)))                     # 查看數(shù)據(jù)規(guī)模

df_details.printSchema()                                                # 數(shù)據(jù)列信息

df_details.orderBy(rand()).show(10,False)                               # 查看數(shù)據(jù)

print('-------------- 進(jìn)行數(shù)據(jù)轉(zhuǎn)換,主要將類別數(shù)據(jù),轉(zhuǎn)換為可通過數(shù)值來度量------------------')

from pyspark.ml.feature import StringIndexer,IndexToString              # StringIndexer可以把字符串的列按照出現(xiàn)頻率進(jìn)行排序,將字符串轉(zhuǎn)化為可度量的

stringIndexer = StringIndexer(inputCol="title", outputCol="title_new")  # 構(gòu)建StringIndexer對(duì)象,設(shè)定輸入列和輸出列

model = stringIndexer.fit(df_details)                                   # 構(gòu)建model模型

indexed = model.transform(df_details)                                   # 使用模型轉(zhuǎn)換數(shù)據(jù),講電影名轉(zhuǎn)換為數(shù)值,可以進(jìn)行度量

indexed.show(10)

indexed.groupBy('title_new').count().orderBy('count',ascending=False).show(10,False)    # 查看分類的數(shù)據(jù)樣式

train,test=indexed.randomSplit([0.75,0.25])                                             # 劃分訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù)

print('--------------- 使用推薦模型ALS算計(jì) ------------------------')

from pyspark.ml.recommendation import ALS

'''
關(guān)于 ALS 的參數(shù):maxIter 最大迭代次數(shù)  ;  regParam 表示最小二乘法中l(wèi)ambda值的大小 ; userCol ,itemCol 用于表征對(duì)象的標(biāo)識(shí),通過指出這兩列后可以,通過它們構(gòu)建起關(guān)系,通過ratingCol表示它們間的關(guān)系。構(gòu)建成評(píng)分矩陣
再本例子中:useCol 是 用戶ID ,itemCol 是電影名 ,ratingCol 是用戶對(duì)電影的評(píng)分。
'''
rec=ALS(maxIter=10,regParam=0.01,userCol='userId',itemCol='title_new',ratingCol='rating',nonnegative=True,coldStartStrategy="drop")   

rec_model=rec.fit(train)                     # 使用模型訓(xùn)練數(shù)據(jù)

predicted_ratings=rec_model.transform(test)  # 應(yīng)用于測(cè)試數(shù)據(jù)

predicted_ratings.printSchema()

predicted_ratings.orderBy(rand()).show(10)   # 參看應(yīng)用模型預(yù)測(cè)的數(shù)據(jù)

print('------------- 引入回歸評(píng)估器來度量 推薦系統(tǒng) --------------')

from pyspark.ml.evaluation import RegressionEvaluator        # RegressionEvaluator 回歸評(píng)估器,它期望兩個(gè)輸入列:預(yù)測(cè)和標(biāo)簽。

evaluator=RegressionEvaluator(metricName='rmse',predictionCol='prediction',labelCol='rating')   # 構(gòu)建回歸評(píng)估器,評(píng)估準(zhǔn)確性

rmse=evaluator.evaluate(predicted_ratings)

print('{}{}'.format("標(biāo)準(zhǔn)誤差:",rmse))                      # 查看使用推薦系統(tǒng)后的預(yù)測(cè)的標(biāo)準(zhǔn)誤差,若標(biāo)準(zhǔn)誤差不是很大的話,可以進(jìn)行下一步操作。

unique_movies=indexed.select('title_new').distinct()        # 篩選出所有電影,使用distinct
unique_movies.count()

all = unique_movies.alias('all')                            # 所有電影df,重命名為 all

watched_movies=indexed.filter(indexed['userId'] == 46).select('title_new').distinct()   # 查看85號(hào)用戶,看過的所有電影

watched_movies.count()

no_46=watched_movies.alias('no_46')     # 46號(hào)用戶看過的電影df,重命名為no_46

total_movies = all.join(no_46, all.title_new == no_46.title_new,how='left')     # 關(guān)聯(lián)得出用戶46沒有觀看評(píng)分的電影。

total_movies.show(10,False)     

remaining_movies=total_movies.where(col("no_46.title_new").isNull()).select(all.title_new).distinct()   # 46號(hào)用戶,沒看過電影的df

remaining_movies=remaining_movies.withColumn("userId",lit(46))          # 添加一列      

recommendations=rec_model.transform(remaining_movies).orderBy('prediction',ascending=False) 

recommendations.show(5,False)   

movie_title = IndexToString(inputCol="title_new", outputCol="title",labels=model.labels)

final_recommendations=movie_title.transform(recommendations)

final_recommendations.show(10,False)            # 但是最后推薦給用戶的預(yù)估評(píng)分都超過了5分,這是個(gè)問題

part1.png
part2.png
part3.png

上一篇:PySpark-ml-隨機(jī)深林
下一篇:PySpark-ml-聚類

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容