如何用Python來搭建一個簡單的推薦系統(tǒng)
在這篇文章中,我們會介紹如何用Python來搭建一個簡單的推薦系統(tǒng)。
本文使用的數(shù)據(jù)集是MovieLens數(shù)據(jù)集,該數(shù)據(jù)集由明尼蘇達大學的Grouplens研究小組整理。它包含1,10和2億個評級。 Movielens還有一個網(wǎng)站,我們可以注冊,撰寫評論并獲得電影推薦。接下來我們就開始實戰(zhàn)演練。
在這篇文章中,我們會使用Movielens構(gòu)建一個基于item的簡易的推薦系統(tǒng)。在開始前,第一件事就是導入pandas和numPy。
import pandas as pd import numpy as np import warnings warnings.filterwarnings('ignore')
接下來,我們使用pandas read_csv()加載數(shù)據(jù)集。數(shù)據(jù)集由制表符分隔,所以我們將\ t傳遞給sep參數(shù)。然后,使用names參數(shù)傳入列名。
df = pd.read_csv('u.data', sep='\t', names=['user_id','item_id','rating','titmestamp'])
接下來查看表頭,檢查一下正在處理的數(shù)據(jù)。
df.head()
如果我們能夠看到電影的標題而不僅僅是ID,那再好不過了。之后加載電影標題并把它與此數(shù)據(jù)集合并。
movie_titles = pd.read_csv('Movie_Titles') movie_titles.head()
由于item_id列相同,我們可以在此列上合并這些數(shù)據(jù)集。
df = pd.merge(df, movie_titles, on='item_id') df.head()
數(shù)據(jù)集中的每一列分部代表:
- user_id - 評級電影的用戶的ID。
- item_id- 電影的ID。
- rating - 用戶為電影提供的評級,介于1和5之間。
- timestamp - 電影評級的時間。
- title - 電影標題。
使用describe或info命令,就可以獲得數(shù)據(jù)集的簡要描述。如果想要真正了解正在使用的數(shù)據(jù)集的話,這一點非常重要。
df.describe()
可以看出,數(shù)據(jù)集共有100003條記錄,電影的平均評分介于3.52-5之間。
現(xiàn)在我們再創(chuàng)建一個dataframe,其中包含每部電影的平均評分和評分數(shù)量。之后,這些評分將用來計算電影之間的相關性。相關性是一種統(tǒng)計指標,表示兩個或多個變量一起波動的程度。相關系數(shù)越高,電影越為相似。
以下例子將使用Pearson相關系數(shù) (Pearson correlation coefficient),該數(shù)字介于-1和1之間,1表示正線性相關,-1表示負相關, 0表示沒有線性相關。也就是說,具有零相關性的電影完全不相似。
我們會使用pandas groupby 功能來創(chuàng)建dataframe。按照標題對數(shù)據(jù)集進行分組,并計算其平均值獲得每部電影的平均評分。
ratings = pd.DataFrame(df.groupby('title')['rating'].mean()) ratings.head()
接下來我們創(chuàng)建number_of_ratings列,這樣就能看到每部電影的評分數(shù)量。完成這步操作后,就可以看到電影的平均評分與電影獲得的評分數(shù)量之間的關系。五星級電影很有可能只被一個人評價,而這種五星電影在統(tǒng)計上是不正確的。
因此,在構(gòu)建推薦系統(tǒng)時,我們需要設置閾值。我們可以使用pandas groupby功能來創(chuàng)建新列,然后按標題欄分組,使用計數(shù)函數(shù)計算每部電影的評分。之后,便可以使用head()函數(shù)查看新的dataframe。
rating ['number_of_ratings'] = df.groupby('title')['rating'].count() ratings.head()
接下來我們使用pandas繪制功能來繪制直方圖,顯示評級的分布:
import matplotlib.pyplot as plt %matplotlib inline ratings['rating'].hist(bins=50)
可以看到,大多數(shù)電影的評分都在2.5-4之間。通過類似的方法還可以將number_of_ratings列可視化。
ratings['number_of_ratings'].hist(bins=60)
從上面的直方圖中可以清楚地看出,多數(shù)電影的評分都很低,評分最高的電影是一些非常有名的電影。
現(xiàn)在讓我們再來看一下電影評級與評分數(shù)量之間的關系。我們可以使用seaborn繪制散點圖,然后使用jointplot()函數(shù)執(zhí)行此操作。
import seaborn as sns sns.jointplot(x='rating', y='number_of_ratings', data=ratings)
從圖中我們可以看出,電影平均評分與評分數(shù)量之間呈正相關關系,電影獲得的評分數(shù)量越多,其平均評分越高。
創(chuàng)建基于item的簡易推薦系統(tǒng)
接下來我們會快速創(chuàng)建一個基于item的簡單的推薦系統(tǒng)。
首先,我們需要將數(shù)據(jù)集轉(zhuǎn)換為矩陣,電影標題為列,user_id為索引,評級為值。完成這一步,我們將得到一個dataframe,其中列是電影標題,行是用戶ID。每列代表所有用戶對電影的所有評級。評級為NAN表示用戶未對這部電影評分。
我們可以用該矩陣來計算單個電影的評級與矩陣中其余電影的相關性,該矩陣可以通過pandas pivot_table實現(xiàn)。
movie_matrix = df.pivot_table(index ='user_id',columns ='title',values ='rating') movie_matrix.head()
接下來讓我們找到評分數(shù)量最多的電影,并選擇其中的兩部電影。然后使用pandas sort_values并將升序設置為false,以便顯示評分最多的電影。然后使用head()函數(shù)來查看評分數(shù)目最多的前十部電影。
ratings.sort_values('number_of_ratings', ascending=False).head(10)
假設一個用戶曾看過Air Force One(1997)和Contact(1997),我們想根據(jù)這兩條觀看記錄向該用戶推薦其他類似的電影,那么這一點可以通過計算這兩部電影的評級與數(shù)據(jù)集中其他電影的評級之間的相關性來實現(xiàn)。第一步是創(chuàng)建一個dataframe,其中包含來自movie_matrix的這些電影的評級。
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之間的相關性。有了這一步,就能夠獲得每部電影的評級與Air Force One電影的評級之間的相關性。
similar_to_air_force_one = movie_matrix.corrwith(AFO_user_rating)
可以看到,Air Force One電影和Till There Was You(1997)之間的相關性是0.867。這表明這兩部電影之間有很強的相似性。
similar_to_air_force_one.head()
還可以計算Contact(1997)的評級與其他電影評級之間的相關性,步驟同上:
similar_to_contact = movie_matrix.corrwith(contact_user_rating)
可以從中發(fā)現(xiàn),Contact(1997)和Till There Was You(1997)之間存在非常強的相關性(0.904)。
similar_to_contact.head()
前邊已經(jīng)提到,并非所有用戶都對所有電影進行了評分,因此,該矩陣中有很多缺失值。為了讓結(jié)果看起來更有吸引力,刪除這些空值并將相關結(jié)果轉(zhuǎn)換為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()
上面這兩個dataframe分別展示了與Contact(1997)和Air Force One(1997)電影最相似的電影。然而,問題出現(xiàn)了,有些電影的實際質(zhì)量非常低,但可能因為一兩位用戶給他們5星評級而被推薦。
這個問題可以通過設置評級數(shù)量的閾值來解決。從早期的直方圖中看到,評級數(shù)量從100開始急劇下降。因此可以將此設置為閾值,但是也可以考慮其他合適的值。為此,我們需要將兩個dataframe與rating datframe中的number_of_ratings列一起加入。
corr_AFO = corr_AFO.join(ratings['number_of_ratings']) corr_contact = corr_contact.join(ratings['number_of_ratings'])corr_AFO.head()corr_contact.head()
現(xiàn)在,我們就能得到與Air Force One(1997)最相似的電影,并把這些電影限制在至少有100條評論的電影中,然后可以按相關列對它們進行排序并查看前10個。
corr_AFO [corr_AFO ['number_of_ratings']> 100] .sort_values(by ='correlation',ascending = False).head(10)
我們注意到Air Force One(1997)與自身相關性最高,這并不奇怪。下一部與Air Force One(1997)最相似的電影是Hunt for Red October,相關系數(shù)為0.554。
顯然,通過更改評論數(shù)量的閾值,我們可以按之前的方式得到不同的結(jié)果。限制評級數(shù)量可以讓我們獲得更好的結(jié)果。
現(xiàn)在重復上邊的步驟,可以看到與Contact(1997)電影最相關的電影:
corr_contact [corr_contact ['number_of_ratings']> 100] .sort_values(by ='Correlation',ascending = False).head(10)
與Contact(1997)最相似的電影是Philadelphia(1993),相關系數(shù)為0.446,有137個評級。所以,如果有人喜歡Contact(1997),我們可以向他們推薦上述電影。
以上是構(gòu)建推薦系統(tǒng)的一種非常簡單的方法,但并不符合行業(yè)標準。后續(xù)的話我們可以通過構(gòu)建基于存儲器的協(xié)同過濾系統(tǒng)來改進該系統(tǒng)。在這種情況下,將數(shù)據(jù)劃分為訓練集和測試集,使用諸如余弦相似性來計算電影之間的相似性;或者構(gòu)建基于模型的協(xié)作過濾系統(tǒng),然后使用Root Mean Squared Error(RMSE)等技術(shù)評估模型。
Github: https://github.com/mwitiderrick/simple-recommender-
英文:How to build a Simple Recommender System in Python
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
vscode配置與python虛擬環(huán)境切換的幾種方式總結(jié)
Python之所以強大,除了語言本身的特性外,更重要的是擁有無所不及的第三方庫,下面這篇文章主要給大家介紹了關于vscode配置與python虛擬環(huán)境切換的幾種方式,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-12-12Python enumerate函數(shù)功能與用法示例
這篇文章主要介紹了Python enumerate函數(shù)功能與用法,結(jié)合實例形式分析了enumerate函數(shù)針對列表、字符串遍歷操作相關使用技巧,需要的朋友可以參考下2019-03-03Django中利用filter與simple_tag為前端自定義函數(shù)的實現(xiàn)方法
這篇文章主要給大家介紹了Django中利用filter與simple_tag為前端自定義函數(shù)的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。2017-06-06python機器學習sklearn實現(xiàn)識別數(shù)字
本文主要介紹了python機器學習sklearn實現(xiàn)識別數(shù)字,主要簡述如何通過sklearn模塊來進行預測和學習,最后再以圖表這種更加直觀的方式展現(xiàn)出來,感興趣的可以了解一下2022-03-03linux系統(tǒng)使用python監(jiān)測系統(tǒng)負載腳本分享
這篇文章主要介紹了linux系統(tǒng)使用python監(jiān)測系統(tǒng)負載腳本,大家參考使用吧2014-01-01Python實現(xiàn)將內(nèi)容寫入文件的五種方法總結(jié)
本篇帶你詳細看一下python將內(nèi)容寫入文件的方法以及細節(jié),主要包括write()方法、writelines()?方法、print()?函數(shù)、使用?csv?模塊、使用?json?模塊,需要的可以參考一下2023-04-04Python字典取值全攻略之高效、簡潔地獲取字典值的多種技巧
這篇文章主要給大家介紹了關于Python字典取值全攻略之高效、簡潔地獲取字典值的多種技巧,dictionary(字典)是除列表以外Python之中最靈活的數(shù)據(jù)類型,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2023-12-12