天天看點

利用python建構一個簡單的推薦系統

本文将利用python建構一個簡單的推薦系統,在此之前讀者需要對pandas和numpy等資料分析包有所了解。

什麼是推薦系統?

推薦系統的目的是通過發現資料集中的模式,為使用者提供與之最為相關的資訊。當你通路Netflix的時候,它也會為你推薦電影。音樂軟體如Spotify及Deezer也使用推薦系統進行音樂推薦。

下圖說明了推薦系統是如何在電子商務網站的上下文中工作的。

利用python建構一個簡單的推薦系統

兩名使用者都在某電商網站購買了A、B兩種産品。當他們産生購買這個動作的時候,兩名使用者之間的相似度便被計算了出來。其中一名使用者除了購買了産品A和B,還購買了C産品,此時推薦系統會根據兩名使用者之間的相似度會為另一名使用者推薦項目C。

推薦系統的主要分類

目前,主流的推薦系統包括基于内容的推薦以及協同過濾推薦。協同過濾簡單來說就是根據使用者對物品或者資訊的偏好,發現物品或者内容本身的相關性,或者是發現使用者的相關性,然後再基于這些關聯性進行推薦。

舉個簡單的例子,如果要向個使用者推薦一部電影,那麼一定是基于他/她的朋友對這部電影的喜愛。基于協同過濾的推薦又可以分為兩類:啟發式推薦算法(Memory-based algorithms)及基于模型的推薦算法(Model-based algorithms)。啟發式推薦算法易于實作,并且推薦結果的可解釋性強。啟發式推薦算法又可以分為兩類:

  1. 基于使用者的協同過濾(User-based collaborative filtering):主要考慮的是使用者和使用者之間的相似度,隻要找出相似使用者喜歡的物品,并預測目标使用者對對應物品的評分,就可以找到評分最高的若幹個物品推薦給使用者。舉個例子,Derrick和Dennis擁有相似的電影喜好,當新電影上映後,Derick對其表示喜歡,那麼就能将這部電影推薦給Dennis。
  2. 基于項目的協同過濾(Item-based collaborative filtering):主要考慮的是物品和物品之間的相似度,隻有找到了目标使用者對某些物品的評分,那麼就可以對相似度高的類似物品進行預測,将評分最高的若幹個相似物品推薦給使用者。舉個例子,如果使用者A、B、C給書籍X,Y的評分都是5分,當使用者D想要買Y書籍的時候,系統會為他推薦X書籍,因為基于使用者A、B、C的評分,系統會認為喜歡Y書籍的人在很大程度上會喜歡X書籍。

基于模型的推薦算法利用

矩陣分解

,有效的緩解了

資料稀疏性

的問題。矩陣分解是一種

降低次元

的方法,對特征進行提取,提高推薦準确度。基于模型的方法包括[決策樹]()、

基于規則的模型

貝葉斯方法

和潛在因素模型。

基于内容的推薦系統會使用到中繼資料,例如流派、制作人、演員、音樂家等來推薦電影或音樂。如果有人看過并喜歡範·迪塞爾主演的《速度與激情》,那麼系統很有可能将他主演的另一部電影《無限戰争》推薦給這些使用者。同樣,你也可以從某些藝術家那裡得到音樂推薦。基于内容的推薦的思想是:如果你喜歡某樣東西,你很可能會喜歡與之相似的東西。

資料集

我們将使用到

MovieLes資料集

,該資料集是關于電影評分的,由明尼蘇達大學的Grouplens研究小組整理,分為1M,10M,20M三個規格。Movielens還有一個網站,可以注冊,撰寫評論并擷取電影推薦。若不想用此資料集,你也可以從

Dataquest

的資料資源中找到更多用于各種資料科學任務的資料集。

推薦系統建構

我們将使用movielens建構一個基于項目相似度的推薦系統,首先導入pandas和numpy。

import pandas as pd 
import numpy as np
import warnings
warnings.filterwarnings('ignore')           

接下來利用pandas中的read_csv()對資料進行加載。資料集中的資料以tab進行分隔,我們需要設定sep = t來指定字元的分隔符号,然後通過names參數傳入列名。

df = pd.read_csv('u.data', sep='\t',names=['user_id','item_id','rating','titmestamp'])           

接下來,檢查正在處理的資料。

df.head()           

相比隻知道電影的ID,能看到它們的标題更為友善。接下來,下載下傳電影的标題并将它們整合到資料集中。

movie_titles = pd.read_csv('Movie_Titles')
movie_titles.head()           

因為item_id列是相同的,我們便可以在此列上對資料進行合并。

df = pd.merge(df, movie_titles, on='item_id')
df.head()           

每列釋義如下:

User_id:使用者ID

Item_id:電影ID

Rating:使用者給電影的評分,介于1到5分之間

Timestamp:對電影進行評分的時間點

Title:電影标題

使用description或info指令,可以得到資料集的簡要描述,以幫助我們更好的了解資料集。

df.describe()           

通過上一步,可以知道電影的平均分為3.52,最高為5分。

接下來建構一個包含每部電影的平均評分和被評分次數的dataframe,用來計算電影間的相關性。相關性是一種統計度量,用來表示兩個或多個變量在一起波動的程度,電影之間的

相關系數

越高,越相似。

在本例中,我們将使用

皮爾遜相關系數

,它的變化範圍為-1到1。當相關系數為1時,為完全正相關;當相關系數為-1時,為完全負相關;相關系數越接近于0,相關度越弱。利用pandas 中的groupby功能建立dataframe,按标題列對資料集進行分組,并計算每部電影的平均分。

ratings = pd.DataFrame(df.groupby('title')['rating'].mean())
ratings.head()           

接下來計算每部電影被評分的次數,觀察它與電影平均評分之間的關系。一部5分的電影很可能隻有一個使用者評分。從統計學上來說,把它視為5分電影是不合理的。

是以,在建構推薦系統時,我們需要為評分次數設定一個門檻值。使用pandas中的 groupby功能建立number_of_ratings列,按title列進行分組,然後使用count函數計算每部電影的被評分次數。之後,使用head()函數檢視新的dataframe。

ratings['number_of_ratings'] = df.groupby('title')['rating'].count()
ratings.head()           

利用pandas中的繪圖功能繪制直方圖,可視化評分分布。

import matplotlib.pyplot as plt
%matplotlib inline
ratings['rating'].hist(bins=50)           

從中可以看出,多數電影的分值在2.5到4分之間。接下來将以同樣的方式對number_of_ratings進行可視化。

ratings['number_of_ratings'].hist(bins=60)           

從直方圖中可以清楚地看出大多數電影都隻有較少的評分,那些評分次數多的電影都擁有較高的知名度。

接下來探索電影評分和被評分次數之間的關系。使用seaborn繪制散點圖,通過jointplot()函數實作。

import seaborn as sns
sns.jointplot(x='rating', y='number_of_ratings', data=ratings)           

從圖中可以看出電影的平均評分和被評分次數之間呈正相關關系。圖表顯示,一部電影的評分越高,平均分也就越高。在為每部電影的評分設定門檻值時,這一點尤其重要。

接下來建構基于項目的推薦系統。我們需要将資料集轉換為一個矩陣,以電影标題為列,以user_id為索引,以評分為值。之後會得到一個dataframe,其中列是movie标題,行是user_id。每列代表所有使用者對所有電影的評分。若評分為NaN(Not a Number),則表示使用者沒有對某一部電影進行評分。矩陣被用來計算電影之間的相關性。使用pandas中的 pivot_table建立電影矩陣。

movie_matrix = df.pivot_table(index='user_id', columns='title', values='rating')
movie_matrix.head()           

接下來,使用pandas中的 sort_values工具,設定升序為false,以便從評分最高的電影中進行選擇,然後使用head()函數檢視分數前10的電影。

ratings.sort_values('number_of_ratings', ascending=False).head(10)           

假設某使用者看過《空軍一号》和《逾時空接觸》,我們想根據觀看曆史向該使用者推薦電影。通過計算這兩個電影和資料集中其他電影的之間的相關性,尋找與之最為相似的電影,為使用者進行推薦。首先,用movie_matrix中的電影評分建立一個dataframe。

AFO_user_rating = movie_matrix['Air Force One (1997)']
contact_user_rating = movie_matrix['Contact (1997)']           

Dataframe中包含user_id和對應使用者給這兩個電影的評分。利用如下代碼進行檢視。

AFO_user_rating.head()
contact_user_rating.head()           

使用pandas中的corwith功能計算兩個dataframe對象的行或列的兩兩相關關系,進而得出每部電影與《空軍一号》電影之間的相關性。

similar_to_air_force_one=movie_matrix.corrwith(AFO_user_rating)           

可以看到,《空軍一号》與《直到有你》之間的相關性是0.867,表明這兩部電影有很強的相似性。

similar_to_air_force_one.head()           

接下來,計算《逾時空接觸》和其他電影之間的相關性。程式與上面相同。

similar_to_contact = movie_matrix.corrwith(contact_user_rating)           

通過計算,我們發現《逾時空接觸》和《直到有你》之間的相關性更強,為0.904。

similar_to_contact.head()           

由于隻有部分使用者對部分電影進行了評分,導緻矩陣中有許多缺失的值。為了使結果看起來更有吸引力,我們将删除null值并将correlation results轉化為dataframe。

corr_contact = pd.DataFrame(similar_to_contact, columns=['Correlation'])
corr_contact.dropna(inplace=True)
corr_contact.head()
corr_AFO = pd.DataFrame(similar_to_air_force_one, columns=['correlation'])
corr_AFO.dropna(inplace=True)
corr_AFO.head()           

通過上述步驟,計算出了與《逾時空接觸》和《空軍一号》最為相似的電影。然而,有些電影被評價的次數很低,最終可能僅僅因為一兩個人給了5分而被推薦。設定門檻值可解決這個問題。從之前的直方圖中我們看到評分次數從100急劇下降,于是我們将門檻值設為100,不過你可以根據自己的需求進行調整。接下來,利用number_of_ratings列将兩個dataframe連接配接起來。

corr_AFO = corr_AFO.join(ratings['number_of_ratings'])
corr_contact = corr_contact.join(ratings['number_of_ratings'])
corr_AFO .head()
corr_contact.head()           

擷取并檢視前10部最為相關的電影。

corr_AFO[corr_AFO['number_of_ratings'] > 100].sort_values(by='correlation', ascending=False).head(10)           

由于門檻值不同,結果也會有所不同。在設定門檻值後,與《空軍一号》最相似的電影是《獵殺紅色十月》,相關系數為0.554。

接下來擷取并檢視與《逾時空接觸》最為相關的前10部電影。

corr_contact[corr_contact['number_of_ratings'] > 100].sort_values(by='Correlation', ascending=False).head(10)           

《逾時空接觸》最相似的電影是《費城》,相關系數為0.446,被評分次數為137。根據此結果,我們可以向喜歡《逾時空接觸》的使用者推薦清單中的電影。

改進

本文所建構的推薦系統可以通過基于記憶的協同過濾方法進行改進。我們可以将資料集劃分為訓練集和測試集,使用諸如

餘弦相似度

之類的方法來計算電影之間的相似度。還可以通過建立基于模型的協同過濾系統,更好地處理可伸縮性和稀疏性問題。同時也可以利用如

均方根誤差(RMSE)

之類的方法對模型進行評估。除此之外,當所處理的資料量十分龐大時,還可以結合深度學習建構推薦系統。自動編碼器和受限的Boltzmann機器也常用于建構進階推薦系統。

以上為譯文

本文由

阿裡雲雲栖社群

組織翻譯。

文章原标題《How to build a Simple Recommender System in Python》,作者:

Derrick Mwiti

,譯者:Elaine,審校:袁虎。

文章為簡譯,更為詳細的内容,請檢視

原文