推薦系統(tǒng)(二):基于用戶的協(xié)同過濾算法

一啸臀、基本原理

協(xié)同過濾中另一種經(jīng)典的方法就是基于用戶的協(xié)同過濾方法贰拿,其思想是先計算用戶u與其它用戶的相似度规哪,然后選取和u最相似的幾個用戶求豫,把他們買過的產(chǎn)品推薦給u。主要也可分為兩步:(1)建立物品-用戶倒排表诉稍,如圖2的上半部分所示蝠嘉;(2)建立用戶相似度矩陣,如圖2的下半部分所示杯巨。


用戶購買記錄

物品-用戶倒排表

基于用戶的協(xié)同過濾算法的相似度的計算方法與基于物品的計算方式相同蚤告。對于與用戶u相似度接近的K個用戶,遍歷他們有過正反饋的物品服爷,計算出用戶u對每一個物品的感興趣程度:
p(u,i)=\sum_{v \in S(u,K)\cap N(i)}w_{uv}r_{vi}

其中杜恰,S(u, k)包含和用戶u興趣最接近的K個用戶,N(i)是對物品i有過行為的用戶集合仍源,w_{uv}是用戶u和用戶v的相似度心褐,r_{vi}表示用戶v對i的興趣,然后根據(jù)感興趣程度由高到低確定N個推薦給用戶u的物品笼踩。

基于用戶協(xié)同和基于物品協(xié)同的區(qū)別

(1)從推薦場景的角度考慮
ItemCF適用于購物網(wǎng)站逗爹,其中用戶的數(shù)量遠(yuǎn)多于物品的數(shù)量,物品數(shù)據(jù)相對穩(wěn)定嚎于,相似度計算量較小掘而,且不必頻繁更新挟冠;UserCF更適用于新聞、博客等社交網(wǎng)絡(luò)袍睡,其內(nèi)容更新非常頻繁知染,即UserCF更注重社會化,而ItemCF更注重個性化斑胜。
(2)從多樣性的角度考慮
即覆蓋率持舆,指推薦系統(tǒng)能否給用于提供多種選擇。由于UserCF更傾向推薦熱門物品伪窖,ItemCF的多樣性遠(yuǎn)好于UserCF,容易發(fā)現(xiàn)并推薦長尾里的物品居兆。
(3)從冷啟動的角度考慮
UserCF中在新用戶對很少物品產(chǎn)生行為后覆山,不能立即對他進(jìn)行個性化推薦,即暫時無法找到興趣相投的用戶泥栖。ItemCF中新用戶只要對一個物品產(chǎn)生行為簇宽,就可以給他推薦和該物品相關(guān)的其它物品。

二吧享,算法實踐

采用GroupLens提供的MovieLens數(shù)據(jù)集魏割,http://www.grouplens.org/node/73。本章使用中等大小的數(shù)據(jù)集钢颂,包含6000多用戶對4000多部電影的100萬條評分钞它。該數(shù)據(jù)集是一個評分?jǐn)?shù)據(jù)集,用戶可以給電影評1-5分5個不同的等級殊鞭。本文著重研究隱反饋數(shù)據(jù)集中TopN推薦問題遭垛,因此忽略了數(shù)據(jù)集中的評分記錄。

1操灿、包的加載與變量定義

該部分定義了所需要的主要變量锯仪,集合采用字典形式的數(shù)據(jù)結(jié)構(gòu)。

import random
import math 
from operator import itemgetter

class UserBasedCF():
    def __init__(self):
        self.n_sim_user = 20
        self.n_rec_user = 10
        
        self.train = {}
        self.test = {}
        
        self.user_sim_matrix = {}
        self.movie_count = 0

2趾盐、數(shù)據(jù)加載

讀取原始CSV文件庶喜,并劃分訓(xùn)練集和測試集,訓(xùn)練集占比87.5%救鲤,同時建立訓(xùn)練集和測試集的用戶字典久窟,記錄每個用戶對電影評分的字典。

  def get_dataset(self,filename,pivot=0.875):
        train_len,test_len = 0,0
        random.seed()
        for line in self.load_file(filename):
            user,movie,rating,timestamp = line.split(',')
            if random.random()<pivot:
                self.train.setdefault(user,{})
                self.train[user][movie] = rating
                train_len += 1
            else:
                self.test.setdefault(user,{})
                self.test[user][movie] = rating
                test_len += 1
        print('Load dataset success!')
        print('train set:%s, test set:%s'% (train_len,test_len))
        
    def load_file(self,filename):
        with open(filename,'r') as f:
            for i,line in enumerate(f):
                if i==0:
                    continue
                yield line.strip('\r\n')

3蜒简、計算相似度矩陣

第一步建立電影-用戶倒排表瘸羡;第二步計算矩陣C,C[i][j]表示同時喜歡電影i和j的用戶數(shù)搓茬,并考慮對活躍用戶的懲罰犹赖;第三步計算用戶間的相似性矩陣队他。

    def calc_user_sim(self):
        movie_user = {}
        for user,movies in self.train.items():
            for movie in movies:
                if movie not in movie_user:
                    movie_user[movie] = set()
                movie_user[movie].add(user)
        print('Build movie-user table success!')
        self.movie_count = len(movie_user)
        
        for movies,users in movie_user.items():
            for u in users:
                for v in users:
                    if u == v:
                        continue
                    self.user_sim_matrix.setdefault(u,{})
                    self.user_sim_matrix[u].setdefault(v,0)
                    self.user_sim_matrix[u][v] += 1/math.log(1+len(users))
        print('Build user co-rated movies matrix success!')
        
        for u,related_users in self.user_sim_matrix.items():
            for v,count in related_users.items():
                self.user_sim_matrix[u][v] = count / math.sqrt(len(self.train[u])*len(self.train[v]))
        print('Calculate user similarity matrix success!')

4、對用戶進(jìn)行推薦

針對目標(biāo)用戶U峻村,找到K部相似的電影麸折,并推薦其N部電影,如果用戶已經(jīng)看過該電影則不推薦粘昨。

      def recommend(self,user):
            K = self.n_sim_user
            N = self.n_rec_user
            rank = {}
            watched_movies = self.train[user]
            

            for v,wuv in sorted(self.user_sim_matrix[user].items(),key=itemgetter(1),reverse=True)[:K]:
                for movie,rvi in self.train[v].items():
                    if movie in watched_movies:
                        continue
                    rank.setdefault(movie,0)
                    rank[movie] += float(wuv)*float(rvi)
            return sorted(rank.items(),key=itemgetter(1),reverse=True)[0:N]

5垢啼、評估指標(biāo)的計算

產(chǎn)生推薦并通過準(zhǔn)確率、召回率和覆蓋率進(jìn)行評估张肾。

def evaluate(self):
    print('Evaluateing starting ...')
    N = self.n_rec_movie
    hit,rec_count,test_count = 0,0,0 
    all_rec_movies = set()
    for i,user in enumerate(self.train):
        test_movies = self.test.get(user,{})
        rec_movies = self.recommend(user)
        for movie,w in rec_movies:
            if movie in test_movies:
                hit += 1
            all_rec_movies.add(movie)
        rec_count += N
        test_count += len(test_movies)
    precision = hit/(1.0*rec_count)
    recall = hit/(1.0*test_count)
    coverage = len(all_rec_movies)/(1.0*self.movie_count)
    print('precision=%.4f, recall=%.4f, coverage=%.4f'%(precision,recall,coverage))

結(jié)果如下所示芭析,由于數(shù)據(jù)量較大,計算速度較慢吞瞪,耐心等待即可馁启。

Load dataset success!
train set:875020, test set:125188
Build movie-user table success!
Build user co-rated movies matrix success!
Calculate user similarity matrix success!
Evaluateing starting ...
precision=0.2322, recall=0.1120, coverage=0.2931

參考資料

[1]. https://blog.csdn.net/m0_37917271/article/details/82498308
[2]. 推薦系統(tǒng)與深度學(xué)習(xí). 黃昕等. 清華大學(xué)出版社. 2019.
[3]. 推薦系統(tǒng)算法實踐. 黃美靈. 電子工業(yè)出版社. 2019.
[4]. 推薦系統(tǒng)算法. 項亮. 人民郵電出版社. 2012.
[5]. 美團機器學(xué)習(xí)實踐. 美團算法團隊. 人民郵電出版社. 2018.

新家孟城口,古木余衰柳芍秆。來者復(fù)為誰惯疙,空悲昔人有⊙叮——王維《輞川集·孟城坳》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末霉颠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荆虱,更是在濱河造成了極大的恐慌蒿偎,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怀读,死亡現(xiàn)場離奇詭異酥郭,居然都是意外死亡,警方通過查閱死者的電腦和手機愿吹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門不从,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人犁跪,你說我怎么就攤上這事椿息。” “怎么了坷衍?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵寝优,是天一觀的道長。 經(jīng)常有香客問我枫耳,道長乏矾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮凄硼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘摊沉。我一直安慰自己,他們只是感情好说墨,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苍柏,像睡著了一般尼斧。 火紅的嫁衣襯著肌膚如雪试吁。 梳的紋絲不亂的頭發(fā)上突颊,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天潘悼,我揣著相機與錄音,去河邊找鬼爬橡。 笑死治唤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的糙申。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼缕陕,長吁一口氣:“原來是場噩夢啊……” “哼疙挺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起铐然,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搀暑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桐罕,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年溅潜,在試婚紗的時候發(fā)現(xiàn)自己被綠了死宣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡毅该,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挡育,到底是詐尸還是另有隱情朴爬,我是刑警寧澤即寒,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布召噩,位于F島的核電站,受9級特大地震影響具滴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜周蹭,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一疲恢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧显拳,春花似錦、人聲如沸杂数。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羊精。三九已至囚玫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抓督,已是汗流浹背束亏。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碍遍,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓揣炕,卻偏偏與公主長得像东跪,于是被迫代替她去往敵國和親畸陡。 傳聞我的和親對象是個殘疾皇子虽填,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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