如何構建一個真實的推薦系統?

AI 前線導讀:隨著互聯網行業的井噴式發展,數據規模呈現爆炸式增長。大數據中蘊含了巨大的價值,但同時也來了很 “信息過載” 的問題。推薦系統作為一個廣泛應用的信息過濾系統,在很多領域取得了巨大的成功。在電子商務上(Amazon,eBay,阿里巴巴),推薦系統為用戶提供個性化產品,發掘用戶潛在需求。那些電商的 “猜你喜歡” 其實就是推薦系統的應用。簡單的說,推薦系統的目標是根據用戶的偏好,為其找到并推薦可能感興趣的項目。

當今機器學習中最有價值的應用之一就是推薦系統。Amazon 將其 35% 的收入歸功于其推薦系統。

譯注:關于 35% 這一數據詳見《The Amazon Recommendations Secret to Selling More Online》(http://rejoiner.com/resources/amazon-recommendations-secret-selling-online/)

評估是研究和開發任何推薦系統的重要組成部分。根據你的業務和可用數據,有很多方法可以評估推薦系統。在本文中,我們會嘗試一些評估方法。

評級預測

在我上一篇文章中《Building and Testing Recommender Systems With Surprise, Step-By-Step 》(https://towardsdatascience.com/building-and-testing-recommender-systems-with-surprise-step-by-step-d4ba702ef80b):使用 Surprise 構建和測試推薦系統,Surprise 以各種機器學習算法為中心來預測用戶對商品條目的評級(即評級預測)。它要求用戶提供明確的反饋,比如讓用戶在購買圖書后對其進行 0~10 星的評級。然后我們用這些數據來建立用戶興趣的檔案。問題是,不是每個人都愿意留下評級,因此數據往往是稀疏的,就像我們之前看到的 Book-Crossing 數據集一樣:

\"\"

譯注:Book-Crossing 數據集可見 http://www2.informatik.uni-freiburg.de/~cziegler/BX/

大多數推薦系統是這樣試圖預測的:如果用戶對相應的圖書進行評級的話,他們會在里面放入什么內容。如果 “NaN” 太多,那么推薦系統就沒有足夠的數據來理解用戶究竟喜歡什么。

但是,如果你能說服用戶給你評級,那么明確的評級是很好的。因此,如果你擁有大量的數據和用戶評級,那么評估指標應該為 RMSEMAE。讓我們展示一個帶有 Surprise 庫的 Movielens 數據集示例。

movies = pd.read_csv('movielens_data/movies.csv')ratings = pd.read_csv('movielens_data/ratings.csv')df = pd.merge(movies, ratings, on='movieId', how='inner')reader = Reader(rating_scale=(0.5, 5))data = Dataset.load_from_df(df[['userId', 'title', 'rating']], reader)trainSet, testSet = train_test_split(data, test_size=.25, random_state=0)algo = SVD(random_state=0)algo.fit(trainSet)predictions = algo.test(testSet)def MAE(predictions):        return accuracy.mae(predictions, verbose=False)def RMSE(predictions):        return accuracy.rmse(predictions, verbose=False)    print(\u0026quot;RMSE: \u0026quot;, RMSE(predictions))print(\u0026quot;MAE: \u0026quot;, MAE(predictions))
ratings_prediction.py

\"\"

Top-N

從網上購物網站到視頻門戶網站,Top-N 推薦系統的身影無處不在。它們為用戶提供他們可能感興趣的 N 個項目的排名列表,以鼓勵用戶瀏覽、下單購買。

譯注:Top-N 推薦系統的介紹可觀看 YouTube 視頻:https://www.youtube.com/watch?v=EeXBdQYs0CQ

Amazon 的推薦系統之一就是 “Top-N” 系統,它可以為個人提供頂級結果列表:

\"\"

Amazon 的 “Top-N” 推薦包括 9 頁,第一頁有 6 項。一個好的推薦系統應該能夠識別某個用戶感興趣的一組 N 個條目。因為我很少在 Amazon 上買書,因此我的 “Top-N” 就差得很遠。換言之,我可能只會點擊或閱讀我的 “Top-N” 列表中的某本書。

下面的腳本為測試集中的每個用戶生成了前 10 條推薦。

def GetTopN(predictions, n=10, minimumRating=4.0):    topN = defaultdict(list)    for userID, movieID, actualRating, estimatedRating, _ in predictions:        if (estimatedRating \u0026gt;= minimumRating):            topN[int(userID)].append((int(movieID), estimatedRating))    for userID, ratings in topN.items():        ratings.sort(key=lambda x: x[1], reverse=True)        topN[int(userID)] = ratings[:n]    return topN    LOOCV = LeaveOneOut(n_splits=1, random_state=1)for trainSet, testSet in LOOCV.split(data):    # Train model without left-out ratings    algo.fit(trainSet)    # Predicts ratings for left-out ratings only    leftOutPredictions = algo.test(testSet)    # Build predictions for all ratings not in the training set    bigTestSet = trainSet.build_anti_testset()    allPredictions = algo.test(bigTestSet)    # Compute top 10 recs for each user    topNPredicted = GetTopN(allPredictions, n=10)
top-N.py

下面是我們預測的 userId 2 和 userId 3 的前 10 項。

\"\"

命中率

讓我們看看生成的前 10 項推薦究竟有多好。為評估前 10 項,我們使用命中率這一指標,也就是說,如果用戶對我們推薦的前 10 項中的一個進行了評級,那么我們就認為這是一個 “命中”。

計算單個用戶命中率的過程如下:

  • 在訓練數據中查找此用戶歷史記錄中的所有項。

  • 有意刪除其中一項條目(使用留一法,一種交叉驗證方法)。

  • 使用所有其他項目為推薦系統提供信息,并要求提供前 10 項推薦。

  • 如果刪除的條目出現在前 10 項推薦中,那么它就是命中的。如果沒有,那就不算命中。

def HitRate(topNPredicted, leftOutPredictions):    hits = 0    total = 0 # For each left-out rating    for leftOut in leftOutPredictions:        userID = leftOut[0]        leftOutMovieID = leftOut[1]        # Is it in the predicted top 10 for this user?        hit = False        for movieID, predictedRating in topNPredicted[int(userID)]:            if (int(leftOutMovieID) == int(movieID)):                hit = True                break        if (hit) :            hits += 1        total += 1    # Compute overall precision    return hits/totalprint(\u0026quot;\Hit Rate: \u0026quot;, HitRate(topNPredicted, leftOutPredictions))
HitRate.py

\"\"

系統的總命中率是命中數除以測試用戶數。它衡量的是我們推薦刪除評級的頻率,越高越好。

如果命中率非常低的話,這只是意味著我們沒有足夠的數據可供使用。就像 Amazon 對我來說,命中率就非常低,因為它沒有足夠的我購買圖書的數據。

基于評級值的命中率

我們還可以通過預測的評級值來細分命中率。在理想情況下,我們希望預測用戶喜歡的電影,因此我們關心的是高評級值而不是低評級值。

def RatingHitRate(topNPredicted, leftOutPredictions):    hits = defaultdict(float)    total = defaultdict(float)    # For each left-out rating    for userID, leftOutMovieID, actualRating, estimatedRating, _ in leftOutPredictions:        # Is it in the predicted top N for this user?        hit = False        for movieID, predictedRating in topNPredicted[int(userID)]:            if (int(leftOutMovieID) == movieID):                hit = True                break        if (hit) :            hits[actualRating] += 1        total[actualRating] += 1    # Compute overall precision    for rating in sorted(hits.keys()):        print(rating, hits[rating] / total[rating])print(\u0026quot;Hit Rate by Rating value: \u0026quot;)RatingHitRate(topNPredicted, leftOutPredictions)
RatingHitRate.py

\"\"

我們的命中率細分正是我們所期望的,評級值為 5 的命中率遠高于 4 或 3。越高越好。

累積命中率

因為我們關心更高的評級,我們可以忽略低于 4 的預測評級,來計算 \u0026gt; = 4 的評級命中率。

def CumulativeHitRate(topNPredicted, leftOutPredictions, ratingCutoff=0):    hits = 0    total = 0    # For each left-out rating    for userID, leftOutMovieID, actualRating, estimatedRating, _ in leftOutPredictions:        # Only look at ability to recommend things the users actually liked...        if (actualRating \u0026gt;= ratingCutoff):            # Is it in the predicted top 10 for this user?            hit = False            for movieID, predictedRating in topNPredicted[int(userID)]:                if (int(leftOutMovieID) == movieID):                    hit = True                    break            if (hit) :                hits += 1            total += 1        # Compute overall precision    return hits/totalprint(\u0026quot;Cumulative Hit Rate (rating \u0026gt;= 4): \u0026quot;, CumulativeHitRate(topNPredicted, leftOutPredictions, 4.0))
CumulativeHitRate.py

\"\"

越高越好。

平均對等命中排名(Average Reciprocal Hit Ranking,ARHR)

常用于 Top-N 推薦系統排名評估的指標,只考慮第一個相關結果出現的地方。我們在推薦用戶排名靠前而不是靠后的產品獲得了更多的好評。越高越好。

def AverageReciprocalHitRank(topNPredicted, leftOutPredictions):    summation = 0    total = 0        # For each left-out rating    for userID, leftOutMovieID, actualRating, estimatedRating, _ in leftOutPredictions:        # Is it in the predicted top N for this user?        hitRank = 0        rank = 0        for movieID, predictedRating in topNPredicted[int(userID)]:            rank = rank + 1            if (int(leftOutMovieID) == movieID):                hitRank = rank                break        if (hitRank \u0026gt; 0) :                summation += 1.0 / hitRank        total += 1    return summation / totalprint(\u0026quot;Average Reciprocal Hit Rank: \u0026quot;, AverageReciprocalHitRank(topNPredicted, leftOutPredictions))view rawAverageReciprocalHitRank.py hosted with ? by GitHub
AverageReciprocalHitRank.py

\"\"

你的第一個真實推薦系統可能質量很低,哪怕是成熟系統,用于新用戶的表現也是一樣。但是,這仍然比沒有推薦系統要好多得多。推薦系統的目的之一,就是在推薦系統中了解用戶 / 新用戶的偏好,這樣他們就可以開始從系統中接收準確的個性化推薦。

然而,如果你剛剛起步的話,那么你的網站就是全新的,這時候推薦系統并不能為任何人提供個性化的推薦,因為這時候并沒有任何人的評價。然后,這就變成了一個系統引導問題。

譯注:有關系統引導問題可參閱:《Learning Preferences of New Users in RecommenderSystems: An Information Theoretic Approach》(https://www.kdd.org/exploration_files/WebKDD08-Al-Rashid.pdf)

本文的Jupyter Notebook 可以在 Github 上找到:https://github.com/susanli2016/Machine-Learning-with-Python/blob/master/Movielens Recommender Metrics.ipynb。

參考文獻:Building Recommender Systems with Machine Learning and AI(《使用機器學習和人工智能構建推薦系統》https://learning.oreilly.com/videos/building-recommender-systems/9781789803273)

原文鏈接:https://towardsdatascience.com/evaluating-a-real-life-recommender-system-error-based-and-ranking-based-84708e3285b

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252223.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252223.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252223.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

volatile的適用場景

介紹 把代碼塊聲明為 synchronized,有兩個重要后果,通常是指該代碼具有 原子性(atomicity)和 可見性(visibility)。 原子性意味著個時刻,只有一個線程能夠執行一段代碼,這段代碼通過…

link和@import的區別

1、link屬于HTML標簽,import是css提供的 2、link是HTML標簽,沒有兼容問題,而import只在IE5以上才能識別 3、頁面被加載時,link會同時被加載,而import引用的css會等到頁面加載完再加載 4、link方式的樣式的權重高于impo…

6.java 代碼塊

代碼塊 在java中用{}括起來的稱為代碼塊,代碼塊可分為以下四種: 普通代碼塊構造代碼塊靜態代碼塊同步代碼塊普通代碼塊 在方法或語句中出現的{}就稱為普通代碼塊。普通代碼塊和一般語句的執行順序由他們在代碼中出現的次序決定,先出現先執行。 普通代碼塊…

C#如何測試代碼運行時間

第一種方式:System.Diagnostics.Stopwatch stopwatch new Stopwatch(); stopwatch.Start(); // 開始監視代碼運行時間 // 需要測試的代碼 .... stopwatch.Stop(); // 停止監視 TimeSpan timespan stopwatch.Elapsed; // 獲取當前實例測量得出的總時間 double …

0074 幾道面試題

昨天參加了惠裝網的面試,有些題不會做的,記錄下來 switch語句能否作用在byte、long、String上 Java1.7以前:byte、short、int、char Java1.7開始:新增String 因此switch語句不能作用在long上,看下面代碼: p…

SpringBoot入門之內嵌Tomcat配置

spring boot默認web程序啟用tomcat內嵌容器tomcat,監聽8080端口,servletPath默認為 / 。需要用到的就是端口、上下文路徑的修改,在spring boot中其修改方法極其簡單,實例如下: server.port8088 server.context-path/test 啟動程序…

第二十二章:動畫(六)

復合動畫您可以混合等待和未等待的調用來創建復合動畫。 例如,假設您希望按鈕在大小擴展的同時旋轉360度然后收縮。ViewExtensions類定義一個方法名稱ScaleTo,它為Scale屬性設置動畫,就像RotateTo為Rotate屬性設置動畫一樣。 Button大小的擴展…

C#操作Excel總結

0. 導入命名空間: 1234using Microsoft.Office.Core;using Microsoft.Office.Interop.Excel;using System.IO;using System.Reflection;1. 如何打開已有excel文檔,或者創建一個新的excel文檔 123Application app new Application();Workbooks wbks app…

Ubuntu16.04用源安裝Nginx+PHP5.6+MySQL5.6

安裝Nginx 1、首先添加nginx_signing.key(必須,否則出錯) $ wget http://nginx.org/keys/nginx_signing.key$ sudo apt-key add nginx_signing.key 2、添加]Nginx](http://nginx.org/)官方提供的源 $ echo "deb http://nginx.org/packages/ubuntu/ trusty ngin…

leetcode -39組合總數

搜就完事了,沒想著優化。唉~太菜,給一個位置標記位置,然后通過該位置向該位置及該位置以下尋找,這樣不存在什么重復回去查找問題。 如果總結大于目標值,回溯一下,如果不大于繼續。 class Solution { public…

避免某個子窗體重復運行的方法(showdialog、show)

在C#中窗口的顯示有兩種方式:模態顯示(showdialog)和非模態顯示(show)。 二者最常見的區別是:模態顯示后,彈出窗口阻止調用窗口的所有消息響應。只有在彈出窗口結束后調用窗口才能繼續。在模態窗…

ubantu之Git使用

本文講述在Ubuntu 14.04 x64環境下,如何安裝Git,配置連接GitHub,并且上傳本地代碼到github。 一. 注冊Git賬戶以及創建倉庫 要想使用github第一步當然是注冊github賬號了。之后就可以創建倉庫了(免費用戶只能建公共倉庫&#xff0…

Java中基礎數據類型分類

Java中的四類八種基本數據類型 第一類:整數類型 byte short int long (int是整形,也屬于整數類型) 第二類:浮點型 float double 第三類:邏輯型 boolean(它只有兩個值可取true false) 第四類&#xff1…

C#如何打包EXE程序生成setup安裝文件

C#如何打包EXE程序生成setup安裝文件作為研發人員,在本機上開發的winform wpf或者控制臺程序需要發給其他人測試時候,一般需要對其進行打包生成setup安裝文件,今天第一次,搜了下資料,記錄如下:注&#xff1…

PHP正則表達式

php正則表達示的定界符 PHP的正則表達示定界符的規定如下: 定界符,不能用a-z A-Z 0-9 其他的都可以用。必須成對出現,有開始就有結束。 我們來例幾個例子: /中間寫正則/ 正確%中間寫正則% 正確^中間寫正則^ 正確中間寫正則 正確(…

最具戲劇性的分析診斷案例——十分鐘鎖定數據庫性能“元兇”

昨天,正好有點空時間想看看書,結果,剛打開書,沒看幾個字兒,接到用戶電話說:一個庫有問題,希望能幫忙看下。因為我知道他們那邊也有自己的專職DBA,于是問:沒讓人給看看嗎&…

Python黑科技:在家遠程遙控公司電腦,python+微信一鍵連接!

有時候需要遠程家里的臺式機使用,因為我平時都是用 MAC 多,但是遠程喚醒只能針對局域網,比較麻煩,于是我想用微信實現遠程喚醒機器。 *注意:全文代碼可左右滑動查看 準備工作 本程序主要是實現遠程管理 Windows10操作系…

c#通過app.manifest使程序以管理員身份運行

通常我們使用c#編寫的程序不會彈出這個提示,也就無法以管理員身分運行。微軟的操作系統使用微軟的產品方法當然是有的,通過app.manifest配置可以使程序打開的時候,彈出UAC提示需要得到允許才可以繼續,這樣就獲得了管理員的權限來執…

Oracle 作業

Oracle 作業 dbms_job與 dbms_scheduler 用于安排和管理作業隊列,通過使用作業,可以使ORACLE數據庫定期執行特定的任務。 一. dbms_job 1.1. 創建 variable jobno number; begin dbms_job.submit(:jobno,proce_t;, sysdate, sysdate1/24/60); commit; end; / 1.2. 參數 Job 輸出…

企業級 Spring Boot 教程 (十四)用restTemplate消費服務

構架工程 創建一個springboot工程,去消費RESTFUL的服務。這個服務是 http: ///gturnquist-quoters.cfapps.io/api/random ,它會隨機返回Json字符串。 Spring Cloud大型企業分布式微服務云架構源碼請加一七九一七四三三八零 在Spring項目中,它…