协同滤波模型的推荐算法(ACM暑校-案例学习)
基于協(xié)同濾波的推薦技術(shù)可以細(xì)分為基于用戶的協(xié)同過濾方法、基于產(chǎn)品的協(xié)同過濾方法、基于模型的協(xié)同過濾方法;本博文進(jìn)行了一一測(cè)試。
1. 數(shù)據(jù)準(zhǔn)備、評(píng)價(jià)指標(biāo)
由于協(xié)同濾波模型需要用到用戶的行為,這里選用MovieLen數(shù)據(jù)集進(jìn)行測(cè)試研究。
MovieLen是明尼蘇達(dá)大學(xué)計(jì)算機(jī)科學(xué)系GroupLens研究中心開發(fā)和維護(hù)的,也是最常用于測(cè)試協(xié)同濾波算法性能的公開數(shù)據(jù)集之一。Movielens提供了大量電影的用戶評(píng)分。完整的版本包括超過了26000000的電影評(píng)分,他們來(lái)源于270000用戶觀看45000部電影的體會(huì)。GroupLens網(wǎng)站上提供的數(shù)據(jù)集不再提供用戶人口統(tǒng)計(jì)信息。因此,這里使用Prajit-Datta在kaggle上提供的部分?jǐn)?shù)據(jù)集。
- 數(shù)據(jù)下載
下載地址:https://www.kaggle.com/prajitdatta/movielens-100k-dataset/data?
該數(shù)據(jù)集包括:1682部電影上943名用戶的100000個(gè)評(píng)分(1-5)。每個(gè)用戶至少為20部電影打分。該數(shù)據(jù)集也為用戶提供簡(jiǎn)單的人口統(tǒng)計(jì)信息(年齡、性別、工作等)。這些數(shù)據(jù)是在1997年9月19日至1998年4月22日的七個(gè)月期間通過Movielens網(wǎng)站(movielens.umn.edu)收集的。此數(shù)據(jù)已被清除-從該數(shù)據(jù)集中刪除了評(píng)分低于20或沒有完整人口統(tǒng)計(jì)信息的用戶。
- 數(shù)據(jù)瀏覽
在解壓文件中,只需要使用u.date/ u.user/ u.item三個(gè)文件。
① 查看用戶圖譜文件
import pandas as pd# load the u.user file into a dataframe u_cols = ['user_id', 'age', 'sex', 'occupation', 'zip_code'] users = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movielens/u.user', sep='|',names=u_cols, encoding='latin-1') users.head()可以看到,u.user文件中主要包含的用戶圖譜,如年齡,性別,職業(yè),zip_code。
② 查看電影描述文件
i_cols = ['movie_id', 'title', 'release date', 'video release date', 'IMDB URL', 'unknow', 'Action', 'Adventure', 'Animation', 'Children\'s', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War','Western'] movies = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movielens/u.item',sep='|', names=i_cols, encoding='latin-1') movies.head()可以看出,u.item文件中主要提供了電影的名字、發(fā)行時(shí)間、IMDB URL和題材等信息。因?yàn)?#xff0c;本編博客主要研究的是協(xié)同濾波算法,因此,電影中的題材等是用不到的,只需要保留movie_id和title就好。
movies = movies[['movie_id', 'title']] movies.head()③ 查看用戶對(duì)電影評(píng)分文件
r_cols = ['user_id', 'movie_id', 'rating', 'timestamp'] ratings = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movielens/u.data',sep='\t', names=r_cols, encoding='latin-1') ratings.head()- 訓(xùn)練數(shù)據(jù)?training data & 測(cè)試數(shù)據(jù) test data
DataFrame包含從1-5的用戶對(duì)電影的評(píng)分。因此,可以將該問題建模為監(jiān)督學(xué)習(xí)的實(shí)例,目的在于預(yù)測(cè)給定用戶和電影的評(píng)分。雖然電影的分?jǐn)?shù)只是1-5的五個(gè)離散值,其實(shí)質(zhì)仍為回歸問題??紤]用戶對(duì)電影的真實(shí)評(píng)分是5:分類模型不能區(qū)分預(yù)測(cè)評(píng)分為1和4的情況。分類模型會(huì)將1-4的評(píng)分都視為錯(cuò)誤分類。然而,回歸模型卻不是這樣子,其對(duì)rating=4的懲罰遠(yuǎn)遠(yuǎn)大于rating=1的情況。
對(duì)于監(jiān)督模型的學(xué)習(xí),重要的一步在于訓(xùn)練集和測(cè)試集的劃分。在本次試驗(yàn)中,用戶評(píng)分?jǐn)?shù)據(jù)中的75%用作模型訓(xùn)練,25%用于模型測(cè)試
from sklearn.model_selection import train_test_split X = ratings.copy() y = ratings['user_id'] # split into training and test datasets, stratified along user_id X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, stratify=y, random_state=42)>>> X_train.shape = (75000, 3) X_test.shape = (25000, 3)- 評(píng)估方法
這里選用根均方差(RMSE=root-mean-square-error)對(duì)模型的推薦性能進(jìn)行評(píng)估。其Python實(shí)現(xiàn)如下所示:
from sklearn.metrics import mean_squared_error from numpy as npdef rmse(y_true, y_pred):return np.sqrt( mean_squared_error(y_true, y_pred) )# Function to compute the RMSE score obtained on the testing set by a model def score(cf_model):# Construct a list of user-movie tuples from the testing datasetid_pairs = zip(X_test['user_id'], X_test['movie_id'])# Predict the rating for every user-movie tupley_pred = np.array([cf_model(user, movie) for (user, movie) in id_pairs])# Extract the actual ratings given by the users in the test datay_true = np.array(X_test['rating'])# Return the final RMSE scorereturn rmse(y_true, y_pred)2. 基于用戶的協(xié)同過濾推薦算法實(shí)例 Users-based
基于用戶的協(xié)同推薦算法把主要的研究精力放在用戶角度,實(shí)質(zhì)上就是具有相同興趣的用戶群體進(jìn)行聚類,然后對(duì)相同類群的用戶進(jìn)行產(chǎn)品推薦。核心在于對(duì)高度稀疏的用戶-產(chǎn)品矩陣進(jìn)行預(yù)測(cè)和填充。PANDAS提供了一個(gè)非常好用的函數(shù)pivot_table去構(gòu)造rating矩陣:
# Build the ratings matrix using pivot_table function r_matrix = X_train.pivot_table(values='rating', index='user_id', columns='movie_id') r_matrix.head(5)該矩陣就是推薦領(lǐng)域最最重要的了:①用戶-產(chǎn)品矩陣是高度稀疏的;②實(shí)際應(yīng)用過程中,從用戶和產(chǎn)品兩個(gè)維度考慮,評(píng)分矩陣是非常非常巨大的。
- 均值Mean角度初步考慮
首先可以構(gòu)建一個(gè)最簡(jiǎn)單的協(xié)同過濾算法,只需輸入用戶ID和電影ID,并輸出所有看過的用戶對(duì)該電影的平均評(píng)分。用戶之間沒有區(qū)別。換言之,每個(gè)用戶的評(píng)分被賦予相等的權(quán)重。其中,有一種完全可能異常情況:有些電影只能在測(cè)試數(shù)據(jù)集進(jìn)行訪問,而在訓(xùn)練數(shù)據(jù)集不存在。該情況下,我們直接設(shè)置一個(gè)baseline,將其默認(rèn)賦值為3.0。
# User Based Collaborative Filter using MEan Rating def cf_user_mean(user_id, movie_id):# Check if movie_id exists in r_matrixif movie_id in r_matrix:# Compute the mean of all the ratings given to the moviemean_rating = r_matrix[movie_id].mean()else:# Default to a rating of 3.0 in the absence of any informationmean_rating = 3.0return mean_rating# Compute RMSE for the Mean model score(cf_user_mean)>>> 1.0234701463131335該方法僅僅適合討論研究,是沒有實(shí)際應(yīng)用價(jià)值的:一方面,用戶對(duì)產(chǎn)品的評(píng)分肯定會(huì)有偏好;另一方面,大部分少數(shù)群體的興趣沒有被認(rèn)真關(guān)注。一種合適的改進(jìn)方法是采用加權(quán)平均weighted mean。
- 加權(quán)均值weighted mean角度考慮
在前面的模型中,我們?yōu)槊恳粋€(gè)用戶分配了等同的權(quán)重。然而,與普通用戶相比,對(duì)那些評(píng)分與所討論問題相似的用戶給予更多的關(guān)注。因此,在前面的模型中,比較合適的方案是為每一個(gè)用戶分配一個(gè)合適的權(quán)重系數(shù)。數(shù)學(xué)可以表示為:
其中,r(u,m)表示為用戶u對(duì)電影m的評(píng)分。對(duì)于相似度測(cè)量,同樣采用余弦距離。
數(shù)據(jù)處理:將rating表中的NAN替換成0,然后用scikit-learn中的cosine_similarity函數(shù)進(jìn)行處理。
r_matrix_dummy = r_matrix.copy().fillna(0) r_matrix_dummy.head() r_matrix_dummy.shape>>> (943, 1647) from sklearn.metrics.pairwise import cosine_similarity cosine_sim = cosine_similarity(r_matrix_dummy, r_matrix_dummy) cosine_sim.shape>>> (943, 943) # Convert into pandas dataframe cosine_sim = pd.DataFrame(cosine_sim, index=r_matrix.index, columns=r_matrix.index) cosine_sim.head() # User Based Collabrative Filter using Weighted Mean Ratings def cf_user_wmean(user_id, movie_id):# Check if movie_id exists in r_matrixif movie_id in r_matrix:sim_scores = cosine_sim[user_id]m_ratings = r_matrix[movie_id]idx = m_ratings[m_ratings.isnull()].indexm_ratings = m_ratings.dropna()sim_scores = sim_scores.drop(idx)wmean_rating = np.dot(sim_scores, m_ratings)/ sim_scores.sum()else:#Default to a rating of 3.0 in the absence of any informationwmean_rating = 3.0return wmean_ratingscore(cf_user_wmean)>>> 1.0174483808407588- 用戶圖譜demographics角度考慮
這是一種相對(duì)而言更加精細(xì)的處理方式。該算法的核心思想是,具有相同圖譜的用戶傾向于有相似的品味。因此,其有效性取決于這樣的假設(shè):女性、青少年或來(lái)自同一地區(qū)的人在電影選擇時(shí)會(huì)有相同的品味。與前面的模型不同,該種算法不考慮用戶對(duì)特定電影的評(píng)分。相反,算法只關(guān)注那些符合特定人群的用戶。
3.?基于產(chǎn)品的協(xié)同過濾推薦算法實(shí)例 Items-based
Items-based和User-based方法本質(zhì)是一致的,就相當(dāng)于將第二節(jié)中的User變成Item。在基于產(chǎn)品的協(xié)同過濾中,我們計(jì)算庫(kù)存中產(chǎn)品的成對(duì)相似性。然后,根據(jù)user_id和movie_id,計(jì)算用戶對(duì)其所有評(píng)分產(chǎn)品的加權(quán)平均值。這個(gè)模型背后的基本思想是:一個(gè)特定的用戶可能會(huì)對(duì)相似的兩個(gè)產(chǎn)品有相似的評(píng)分。
4. 基于模型的方法 Model-based
到目前為止,上面的協(xié)同過濾算法被稱為memory-based的過濾。因?yàn)樗麄冎焕孟嗨菩远攘縼?lái)得出結(jié)果,并沒有從數(shù)據(jù)中學(xué)習(xí)任何參數(shù),或者為數(shù)據(jù)分配類/集群。并沒有用到機(jī)械學(xué)習(xí)算法的威力。
- 以聚類為核心的協(xié)同過濾算法 - Clustering
weighted mean-based 的濾波算法,考慮到了每一位用戶的評(píng)分,最后進(jìn)行加權(quán);相反,demographic-based濾波算法僅僅考慮了‘某個(gè)圈子’的用戶,最后進(jìn)行平均。通常來(lái)說,weighted mean-based取得的結(jié)果會(huì)好于demographic-based,因?yàn)榭紤]的相對(duì)來(lái)說更廣一點(diǎn)。但是,這兩種方法僅僅用到了最直接、最粗淺的信息,一種解決方案是進(jìn)行多維度用戶刻畫,進(jìn)行利用機(jī)器學(xué)習(xí)算法解決高緯度數(shù)據(jù)處理問題。簡(jiǎn)單說,精準(zhǔn)的推薦結(jié)果不一定唯一依賴考慮所有用戶的感受!
demographic-based算法的缺點(diǎn)來(lái)源于他的假設(shè):來(lái)自某個(gè)相同圖譜的用戶具有相同的想法和評(píng)分。這種極端的思考模式造成了算法的粗淺。Clustering-based方法,如k-means, 就是為了改善這種情況:將用戶分組到一個(gè)群集中,然后在預(yù)測(cè)評(píng)分時(shí)只考慮來(lái)自同一個(gè)群集中的用戶。下面以KNN-based clustering為例,構(gòu)建相關(guān)的協(xié)同過濾算法。步驟如下 ①找出與用戶u對(duì)電影m評(píng)分最相似的k個(gè)最近鄰;②輸出k個(gè)用戶對(duì)電影m評(píng)分的平均值。
可以直接采用Python中的surprise(Simple Python Recommandation System Engine)庫(kù)實(shí)現(xiàn)。Windows 平臺(tái)下下載方式為:pip install scikit-surprise.
# Import the required classes and methods from the surprise library from surprise import Reader, Dataset, KNNBasic, evaluate # Define a Reader object - The Reader object helps in parsing the file or dataframe containing ratings reader = Reader() # Create the dataset to be used for building the filter data = Dataset.load_from_df(ratings, reader) # Define the algorithm object knn = KNNBasic() # Evaluate the performance in terms of RMSE evaluate(knn, data, measures=['RMSE'])從輸出結(jié)果中,我們能夠看出來(lái)。surprise庫(kù)將所有的評(píng)分?jǐn)?shù)據(jù)劃分為5個(gè)文件包,其中4個(gè)文件包用于算法訓(xùn)練,第5個(gè)文件包用于模型測(cè)試。這樣的過程重復(fù)了5次。
- 監(jiān)督學(xué)習(xí)和降維方法
對(duì)于mxn大小的評(píng)分矩陣,每一行代表m個(gè)用戶中的一個(gè)對(duì)所有電影的評(píng)分;每一列代表n個(gè)電影中的一個(gè)接受所有用戶的評(píng)分。前面已經(jīng)看到了,該評(píng)分矩陣是非常稀疏的。通過監(jiān)督學(xué)習(xí)的方法,我們可以嘗試將這個(gè)高度稀疏的矩陣補(bǔ)全。
最簡(jiǎn)單的思考是,我們可以利用mx(n-1)的評(píng)分矩陣進(jìn)行模型的監(jiān)督訓(xùn)練,然后對(duì)m*1的未知評(píng)分進(jìn)行預(yù)測(cè)。如此重復(fù)n次,那么評(píng)分矩陣將有可能完全被填充。理想是豐滿的,現(xiàn)實(shí)的骨感的。因?yàn)?#xff0c;一開始我們用的mx(n-1)的模型訓(xùn)練矩陣就是高度稀疏的~~~(目前也沒辦法解決這個(gè)事,工程上的一種處理手段是用所屬的列的均值或中值來(lái)填充缺失值,但是考慮到rating矩陣高達(dá)90%的系數(shù),計(jì)算的均值和中位數(shù)一定會(huì)引進(jìn)很大的偏差;同時(shí)降維技術(shù),PCA/SVD也不能處理如此稀疏的情況)
可以借鑒的一種思路是,Simon Funk在處理Netflix Problem時(shí),將mx(n-1)的模型訓(xùn)練矩陣壓縮到了更低的維度mxd (d << n),這種處理方式稱為SVD-like,其實(shí)效果也比較一般。
- 火極一時(shí)的推薦算法-奇異值分解 Singular-value decomposition
本質(zhì)上,奇異值分解是一種矩陣因子技術(shù),其輸入為大型矩陣A,輸出為小矩陣U和V。其中,Σ為對(duì)角矩陣用于吃調(diào)整數(shù)據(jù)的尺度。對(duì)于U矩陣,其實(shí)質(zhì)表征的是用戶主成分,英文專有名詞對(duì)應(yīng)user-embedding矩陣;V矩陣,其實(shí)質(zhì)表征的是產(chǎn)品主成分,英文專有名詞對(duì)應(yīng)item-embedding矩陣。
和大多數(shù)機(jī)器學(xué)習(xí)算法一樣,傳統(tǒng)的SVD矩陣對(duì)極其稀疏的評(píng)分矩陣是沒有效益的。然而,SimonFunk找到了解決這個(gè)問題的方法,他的解決方案(SVD++)促成了了推薦系統(tǒng)領(lǐng)域最著名的算法之一。該方法可以利用高度稀疏的評(píng)分矩陣A,生成兩個(gè)非常稠密的user-embedding矩陣U和item-embedding矩陣V。這些稠密的矩陣(U,V)直接解決了原始數(shù)據(jù)A高度稀疏的難題。surprise庫(kù)也集成了該算法,調(diào)用如下:
#Import SVD from surprise import SVD #Define the SVD algorithm object svd = SVD() #Evaluate the performance in terms of RMSE evaluate(svd, data, measures=['RMSE'])?
總結(jié)
以上是生活随笔為你收集整理的协同滤波模型的推荐算法(ACM暑校-案例学习)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《南方都市报》:中国互联网“公共性”正在
- 下一篇: 混合模型的推荐算法(ACM暑校-案例学习