Python實(shí)現(xiàn)推薦系統(tǒng)

兩種最普遍的推薦系統(tǒng)的類型是基于內(nèi)容和協(xié)同過(guò)濾(CF)。協(xié)同過(guò)濾基于用戶對(duì)產(chǎn)品的態(tài)度產(chǎn)生推薦,基于內(nèi)容的推薦系統(tǒng)基于物品屬性的相似性進(jìn)行推薦。CF可以分為基于內(nèi)存的協(xié)同過(guò)濾和基于模型的協(xié)同過(guò)濾。

我們將使用MovieLens數(shù)據(jù)集,它是在實(shí)現(xiàn)和測(cè)試推薦引擎時(shí)所使用的最常見(jiàn)的數(shù)據(jù)集之一,包含來(lái)自943個(gè)用戶以及精選的1682部電影的評(píng)分。數(shù)據(jù)下載地址

導(dǎo)入numpy和pandas庫(kù)


import numpy as np

import pandas as pd

讀入u.data數(shù)據(jù)文件


header = ['user_id', 'item_id', 'rating', 'timestamp']

df = pd.read_csv('u.data', sep = '\t', names = header)

查看用戶和電影的數(shù)量


n_users = df.user_id.unique().shape[0]

n_items = df.item_id.unique().shape[0]

print 'Number of users = ' + str(n_users) + ' | Number of movies = ' + str(n_items)


Number of users = 943 | Number of movies = 1682

使用scikit-learn庫(kù)將數(shù)據(jù)集分割成測(cè)試集和訓(xùn)練集,調(diào)用Cross_validation.train_test_split根據(jù)測(cè)試樣本的比例(test_size)將數(shù)據(jù)混洗并分割成兩個(gè)數(shù)據(jù)集。


from sklearn import cross_validation as cv

train_data,test_data = cv.train_test_split(df, test_size = 0.25)

基于內(nèi)存的協(xié)同過(guò)濾

基于內(nèi)存的協(xié)同過(guò)濾方法可以分為兩個(gè)部分:用戶-產(chǎn)品協(xié)同過(guò)濾和產(chǎn)品-產(chǎn)品協(xié)同過(guò)濾。用戶-產(chǎn)品協(xié)同過(guò)濾將選取一個(gè)特定的用戶,基于打分的相似性發(fā)現(xiàn)類似于該用戶的用戶,并推薦那些相似用戶喜歡的產(chǎn)品。產(chǎn)品-產(chǎn)品協(xié)同過(guò)濾會(huì)選取一個(gè)產(chǎn)品,發(fā)現(xiàn)喜歡該產(chǎn)品的用戶,并找到這些相似用戶還喜歡的其它產(chǎn)品。

用戶-產(chǎn)品協(xié)同過(guò)濾:“喜歡這東西的人也喜歡……”

產(chǎn)品-產(chǎn)品協(xié)同過(guò)濾:“像你一樣的人也喜歡……”

在這兩種情況下,從整個(gè)數(shù)據(jù)集構(gòu)建一個(gè)用戶產(chǎn)品矩陣。

用戶產(chǎn)品矩陣的例子:

計(jì)算相似性,并創(chuàng)建一個(gè)相似性矩陣。

在產(chǎn)品-產(chǎn)品協(xié)同過(guò)濾中的產(chǎn)品之間的相似性是通過(guò)觀察所有對(duì)兩個(gè)產(chǎn)品打分的用戶來(lái)度量的。

在用戶-產(chǎn)品協(xié)同過(guò)濾中的用戶之間的相似性是通過(guò)觀察所有同時(shí)被兩個(gè)用戶打分的產(chǎn)品來(lái)度量的。

通常用于推薦系統(tǒng)中的距離矩陣是余弦相似性,其中,打分被看成n維空間中的向量,而相似性是基于這些向量之間的角度進(jìn)行計(jì)算的。用戶a和m的余弦相似性可以用下面的公式進(jìn)行計(jì)算:

image
image

要計(jì)算產(chǎn)品m和b之間的相似性,使用公式:

image
image

創(chuàng)建用戶產(chǎn)品矩陣,針對(duì)測(cè)試數(shù)據(jù)和訓(xùn)練數(shù)據(jù),創(chuàng)建兩個(gè)矩陣:


train_data_matrix = np.zeros((n_users,n_items))

for line in train_data.itertuples():

train_data_matrix[line[1]-1, line[2]-1] = line[3]

test_data_matrix = np.zeros((n_users, n_items))

for line in test_data.itertuples():

test_data_matrix[line[1]-1, line[2]-1] = line[3]

使用sklearn的pairwise_distances函數(shù)來(lái)計(jì)算余弦相似性。


from sklearn.metrics.pairwise import pairwise_distances

user_similarity = pairwise_distances(train_data_matrix, metric = "cosine")

item_similarity = pairwise_distances(train_data_matrix.T, metric = "cosine")

已經(jīng)創(chuàng)建了相似性矩陣:user_similarity和item_similarity,因此,可以通過(guò)基于用戶的CF應(yīng)用下面的公式做出預(yù)測(cè):

可以將用戶k和用戶a之間的相似性看成權(quán)重,乘以相似用戶a(校正的平均評(píng)分用戶)的評(píng)分,這里需要規(guī)范化該值,使得打分位于1到5之間,最后對(duì)嘗試預(yù)測(cè)的用戶的平均評(píng)分求和。

基于產(chǎn)品的CF應(yīng)用下面的公司進(jìn)行預(yù)測(cè),此時(shí)無(wú)需糾正用戶的平均打分


def predict(rating, similarity, type = 'user'):

if type == 'user':

mean_user_rating = rating.mean(axis = 1)

rating_diff = (rating - mean_user_rating[:,np.newaxis])

pred = mean_user_rating[:,np.newaxis] + similarity.dot(rating_diff) / np.array([np.abs(similarity).sum(axis=1)]).T

elif type == 'item':

pred = rating.dot(similarity) / np.array([np.abs(similarity).sum(axis=1)])

return pred


item_prediction = predict(train_data_matrix, item_similarity, type = 'item')

user_prediction = predict(train_data_matrix, user_similarity, type = 'user')

評(píng)估

這里采用均方根誤差(RMSE)來(lái)度量預(yù)測(cè)評(píng)分的準(zhǔn)確性

可以使用sklearn的mean_square_error(MSE)函數(shù),其中RMSE僅僅是MSE的平方根。


from sklearn.metrics import mean_squared_error

from math import sqrt

def rmse(prediction, ground_truth):

prediction = prediction[ground_truth.nonzero()].flatten()

ground_truth = ground_truth[ground_truth.nonzero()].flatten()

return sqrt(mean_squared_error(prediction, ground_truth))


print 'User based CF RMSE: ' + str(rmse(user_prediction, test_data_matrix))

print 'Item based CF RMSe: ' + str(rmse(item_prediction, test_data_matrix))


User based CF RMSE: 3.12466203536

Item based CF RMSe: 3.45056350625

可以看出,基于內(nèi)存的算法很容易實(shí)現(xiàn)并產(chǎn)生合理的預(yù)測(cè)質(zhì)量。

基于模型的協(xié)同過(guò)濾

基于模型的協(xié)同過(guò)濾是基于矩陣分解(MF)的,矩陣分解廣泛應(yīng)用于推薦系統(tǒng)中,它比基于內(nèi)存的CF有更好的擴(kuò)展性和稀疏性。MF的目標(biāo)是從已知的評(píng)分中學(xué)習(xí)用戶的潛在喜好和產(chǎn)品的潛在屬性,隨后通過(guò)用戶和產(chǎn)品的潛在特征的點(diǎn)積來(lái)預(yù)測(cè)未知的評(píng)分。

計(jì)算MovieLens數(shù)據(jù)集的稀疏度:


sparsity = round(1.0 - len(df) / float(n_users*n_items),3)

print 'The sparsity level of MovieLen100K is ' + str(sparsity * 100) + '%'


The sparsity level of MovieLen100K is 93.7%

SVD

一般的方程可以表示為:

image
image

給定m * n矩陣X:

U 是一個(gè)(m * r)正交矩陣

S 是一個(gè)對(duì)角線上為非負(fù)實(shí)數(shù)的(r * r)對(duì)角矩陣

V^T是一個(gè)(r * n)正交矩陣

S的對(duì)角線上的元素被稱為X的奇異值。

陣X可以被分解成U,S和V。U矩陣表示對(duì)應(yīng)于隱藏特性空間中的用戶的特性矩陣,而V矩陣表示對(duì)應(yīng)于隱藏特性空間中的產(chǎn)品的特性矩陣。

現(xiàn)在,可以通過(guò)U, S和V^T的點(diǎn)積進(jìn)行預(yù)測(cè)了:


import scipy.sparse as sp

from scipy.sparse.linalg import svds

u, s, vt = svds(train_data_matrix, k = 20)

s_diag_matrix = np.diag(s)

x_pred = np.dot(np.dot(u,s_diag_matrix),vt)

print 'User-based CF MSE: ' + str(rmse(x_pred, test_data_matrix))


User-based CF MSE: 2.72035726617

總結(jié):

實(shí)現(xiàn)了簡(jiǎn)單的協(xié)同過(guò)濾方法,包括基于內(nèi)存的CF和基于模型的CF

基于內(nèi)存的模型是基于產(chǎn)品或用戶之間的相似性,這里采用余弦相似性。

基于模型的CD是基于矩陣分解,采用SVD來(lái)分解矩陣

標(biāo)準(zhǔn)的協(xié)同過(guò)濾方法在面對(duì)冷啟動(dòng)的情況時(shí)表現(xiàn)不佳。

參考資料

Implementing your own recommender systems in Python

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,346評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,421評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,534評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,767評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,916評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,156評(píng)論 1 290
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容

  • 歡迎關(guān)注【機(jī)器學(xué)習(xí)之路】公眾號(hào) 1。http://www.voidcn.com/blog/u013713010/a...
    大海一滴寫(xiě)字的地方閱讀 4,703評(píng)論 0 16
  • 推薦系統(tǒng)的主要方法 一、基于內(nèi)容的推薦算法 網(wǎng)絡(luò)基于內(nèi)容的推薦系統(tǒng),也稱CB(Content-based Reco...
    Arya鑫閱讀 3,606評(píng)論 1 6
  • 什么是協(xié)同過(guò)濾 協(xié)同過(guò)濾推薦(Collaborative Filtering recommendation)是在信...
    小灰灰besty閱讀 34,498評(píng)論 7 52
  • 這篇文章的技術(shù)難度會(huì)低一些,主要是對(duì)推薦系統(tǒng)所涉及到的各部分內(nèi)容進(jìn)行介紹,以及給出一些推薦系統(tǒng)的常用算法,比起技術(shù)...
    我偏笑_NSNirvana閱讀 12,127評(píng)論 5 89
  • 說(shuō)起要去我家的事情,我一頭亂麻。姑姑說(shuō)借輛車(chē),我怕好久沒(méi)碰過(guò)車(chē),又不是自己的。想了一圈,表姐不可靠,必然會(huì)背后給我...
    傷城滿樓閱讀 186評(píng)論 0 0