本文將教大家用Python中基于模型的協同過濾構建推薦系統,這種推薦系統經常被用于音樂、視頻網站等。
推薦系統廣泛應用于音樂、電影、書籍、新聞、研究文章、餐館等產品的推薦。
構建推薦系統有兩種常用方法:
- 協同過濾:https://en.wikipedia.org/wiki/Collaborative_filtering
- 基于內容的篩選:https://developers.google.com/machine-learning/recommendation/content-based/basics
協同過濾方法通過從許多其他用戶(協作)收集偏好信息來預測(過濾)用戶對產品的興趣。協同過濾方法背后的假設是,如果一個人 P1 和另一個人 P2 對某個問題有相同的意見,P1比隨機選擇的人更有可能分享P2對不同問題的意見。
基于內容的過濾方法利用產品特性/屬性,根據其他用戶之前的行為或對產品的評價等明確反饋,推薦與用戶喜歡的產品相似的其他產品。
推薦系統可以使用這兩種方法中的一種或兩種。
在本文中,將使用 Kaggle Netflix prize 數據集來演示如何使用基于模型的協同過濾方法在 Python 中構建推薦系統。
本文其余部分安排如下:
- 協同過濾概述
- 用 Python 構建推薦系統
- 總結
1、協同過濾概述
協同過濾背后的主要思想是,一個人經常從另一個興趣相似的人那里得到最佳推薦。協同過濾使用各種技術來匹配興趣相似的人,并基于共同的興趣給出推薦。
協同過濾系統的高級工作流程如下:
- 用戶對項目(如電影、書籍)進行評分,以表達他或她對項目的偏好;
- 系統將評分視為用戶對項目興趣的程度;
- 系統會將此用戶的評分與其他用戶的評分進行匹配,并找到具有最相似評分的人;
- 系統推薦相似用戶評分較高但尚未被該用戶評分的項目。
通常,協同過濾系統通過兩個步驟向給定用戶推薦產品:
- 第1步:尋找與給定用戶共享相同評級模式的人;
- 第2步:使用步驟1中找到的用戶的評分來計算給定用戶對產品的評分預測。
這稱為基于用戶的協作過濾。這種方法的一個具體實現是基于用戶的最近鄰算法。
另一種選擇是,基于項目的協同過濾(例如,對x感興趣的用戶也對y感興趣)以項目為中心的方式工作:
- 第1步:建立一個項目--項目矩陣的評分關系對項目;
- 第2步:通過檢查矩陣并匹配用戶的評分數據,預測當前用戶對產品的評分。
有兩種類型的協同過濾系統:
- 基于模型
- 基于內存
在一個基于模型的系統中,我們使用不同的機器學習算法開發模型來預測用戶對未評分項目的評分。基于模型的協同過濾算法有很多,如奇異值分解(SVD)、貝葉斯網絡、聚類模型等。
基于內存的系統使用用戶的評分數據來計算用戶或項目之間的相似度。這類系統的典型例子是基于鄰域的方法和基于項/基于用戶的 top-N 建議。
本文介紹了如何利用 SVD 模型構建一個基于模型的協同過濾系統。
2、用Python構建推薦系統
下面,將給大家詳細介紹用 Python 構建推薦系統的流程。
2.1 安裝庫
有多個Python庫可用于構建推薦系統(例如 Python scikit Surprise、基于Spark RDD的協同過濾API)。我在本文中使用 Python scikit Surprise 庫進行演示。
可以按如下方式安裝庫:
pip install scikit-surprise
2.2 加載數據
如前所述,我在本文中使用Kaggle Netflix prize數據集。有可用于不同目的的多個數據文件。本文中使用了以下數據文件:
訓練數據:
- Combined_data_1.txt
- Combined_data_2.txt
- Combined_data_3.txt
- Combined_data_4.txt
電影標題數據文件:
- movie_titles.csv
由于訓練數據集太大,無法在筆記本電腦上處理。 因此,為了方便演示,我僅從每個訓練數據文件中加載前 100,000 條記錄。
將訓練數據文件下載到本地計算機上之后,可以將每個訓練數據文件中的前 100,000 條記錄作為Pandas 數據幀加載到內存中,如下所示:
def readFile(file_path, rows=100000):
data_dict = {'Cust_Id' : [], 'Movie_Id' : [], 'Rating' : [], 'Date' : []}
f = open(file_path, "r")
count = 0
for line in f:
count += 1
if count > rows:
break
if ':' in line:
movidId = line[:-2] # remove the last character ':'
movieId = int(movidId)
else:
customerID, rating, date = line.split(',')
data_dict['Cust_Id'].Append(customerID)
data_dict['Movie_Id'].append(movieId)
data_dict['Rating'].append(rating)
data_dict['Date'].append(date.rstrip("n"))
f.close()
return pd.DataFrame(data_dict)
df1 = readFile('./data/netflix/combined_data_1.txt', rows=100000)
df2 = readFile('./data/netflix/combined_data_2.txt', rows=100000)
df3 = readFile('./data/netflix/combined_data_3.txt', rows=100000)
df4 = readFile('./data/netflix/combined_data_4.txt', rows=100000)
df1['Rating'] = df1['Rating'].astype(float)
df2['Rating'] = df2['Rating'].astype(float)
df3['Rating'] = df3['Rating'].astype(float)
df4['Rating'] = df4['Rating'].astype(float)
針對訓練數據的不同部分所產生的不同數據幀如下組合:
df = df1.copy()
df = df.append(df2)
df = df.append(df3)
df = df.append(df4)
df.index = np.arange(0,len(df))
df.head(10)
接下來我們來把 movie-titles 文件可以作為 Pandas 數據幀加載到內存中:
df_title = pd.read_csv('./data/netflix/movie_titles.csv', encoding = "ISO-8859-1", header = None, names = ['Movie_Id', 'Year', 'Name'])
df_title.head(10)
2.3 訓練評估模型
Surprise中的數據集模塊提供了從文件、Pandas 數據幀或內置數據集(如ml-100k(MovieLens 100k)加載數據的各種不同方法,例如:
- Dataset.load_builtin()
- Dataset.load_from_file()
- Dataset.load_from_df()
在本文中,我使用 load_from_df()方法從 Pandas 數據幀加載數據。
Surprise中的 Reader 類用于解析包含用戶、項目和用戶對項目的評分文件。默認格式是每個評分存儲在訂單用戶項目評分的單獨一行中。此順序和分隔符可使用以下參數進行配置:
- line_format 是類似于“ item user rating”的字符串,用于指示字段名稱用空格分隔的數據順序;
- sep 用于指定字段之間的分隔符,例如空格,“,”等;
- rating_scale 用于指定評分等級。默認值為(1,5);
- skip_lines 用于指示文件開頭要跳過的行數,默認值為 0。
本文將使用默認設置,項、用戶、等級分別對應于數據幀中的 Cust_Id,Movie_Id 和 Rating 列。
Surprise 庫包含了構建推薦系統的多個模型/算法的實現,如 SVD、概率矩陣分解(PMF)、非負矩陣分解(NMF)等,本文使用的是 SVD 模型。
下面的代碼是從 Pandas 數據幀中加載數據并創建一個 SVD 模型實例:
from surprise import Reader, Dataset, SVD
from surprise.model_selection.validation import cross_validate
reader = Reader()
data = Dataset.load_from_df(df[['Cust_Id', 'Movie_Id', 'Rating']], reader)
svd = SVD()
產品推薦的數據和模型準備好后,可以使用交叉驗證對模型進行評估,如下所示:
# 運行5倍交叉驗證并打印結果
cross_validate(svd, data, measures=['RMSE', 'MAE'], cv=5, verbose=True)
以下是 SVD 模型交叉驗證的結果:
一旦模型被評估到我們滿意的程度,我們就可以使用整個訓練數據集重新訓練模型:
trainset = data.build_full_trainset()
svd.fit(trainset)
2.4 推薦產品
當推薦模型經過適當的訓練后,就可以用來進行預測。
例如,給定一個用戶(例如,客戶Id 785314),我們可以使用經過訓練的模型來預測用戶對不同產品(即 Movie titles)的評級:
titles = df_title.copy()
titles['Estimate_Score'] = titles['Movie_Id'].apply(lambda x: svd.predict(785314, x).est)
為了向給定用戶推薦產品(即電影),我們可以按預測收視率的降序對電影列表進行排序,并將前N部電影作為推薦:
titles = titles.sort_values(by=['Estimate_Score'], ascending=False)
titles.head(10)
以下是向客戶 Id 為 785314 的用戶推薦的前 10 部電影:
3、總結
在本文中,我使用了 scikit Surprise 庫和 Kaggle Netflix prize 數據集來演示如何使用基于模型的協作過濾方法在 Python 中構建推薦系統。
如本文開頭所述,數據集太大,無法在筆記本電腦或任何傳統的個人計算機上處理。 因此,出于演示目的,我僅從每個訓練數據集文件中加載了前 100,000 條記錄。
在實際應用程序的設置中,我建議將 Spark 與 Koalas 一起使用,或者在 Spark MLLib 中使用Alteraternating Least Squares(ALS)算法來實現協作過濾系統并在 Spark 集群上運行。
Github 源代碼及項目地址:https://github.com/yzzhang/machine-learning/tree/master/recommender
--END--
本文作者張躍峰博士,原文鏈接:https://towardsdatascience.com/machine-learning-for-building-recommender-system-in-python-9e4922dd7e97
翻譯:未艾信息(www.weainfo.net)
喜歡本文的同學記得轉發+點贊~
更多內容,歡迎大家關注我們的公眾號:為AI吶喊(weainahan)