一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

推薦算法實(shí)戰(zhàn)項(xiàng)目:物品協(xié)同過濾算法(ItemCF)原理以及案例實(shí)戰(zhàn)(附完整 Python 代碼)

 昵稱21609410 2024-03-25 發(fā)布于黑龍江

協(xié)同過濾(collaborative filtering)是一種在推薦系統(tǒng)中廣泛使用的技術(shù)。該技術(shù)通過分析用戶或者事物之間的相似性,來預(yù)測用戶可能感興趣的內(nèi)容并將此內(nèi)容推薦給用戶。

這里的相似性可以是人口特征的相似性,也可以是歷史瀏覽內(nèi)容的相似性,還可以是個(gè)人通過一定機(jī)制給與某個(gè)事物的回應(yīng)。比如,A和B是無話不談的好朋友,并且都喜歡看電影,那么協(xié)同過濾會(huì)認(rèn)為A和B的相似度很高,會(huì)將A喜歡但是B沒有關(guān)注的電影推薦給B,反之亦然。

協(xié)同過濾推薦分為3種類型:

基于用戶(user-based)的協(xié)同過濾(UserCF)
基于物品(item-based)的協(xié)同過濾(ItemCF算法)
基于模型(model-based)的協(xié)同過濾 (ModelCF算法)
技術(shù)提升
技術(shù)要學(xué)會(huì)分享、交流,不建議閉門造車。一個(gè)人走的很快、一堆人可以走的更遠(yuǎn)。

文章中的完整源碼、資料、數(shù)據(jù)、技術(shù)交流提升, 均可加知識星球交流群獲取,群友已超過2000人,添加時(shí)切記的備注方式為:來源+興趣方向,方便找到志同道合的朋友vb.net教程C#教程python教程。

算法原理
ItemCF算法是目前業(yè)界使用最廣泛的算法之一,亞馬遜、Netflix、YouTube的推薦算法的基礎(chǔ)都是基于ItemCF。

不知道大家平時(shí)在網(wǎng)上購物的時(shí)候有沒有這樣的體驗(yàn),比如你在網(wǎng)上商城下單了一個(gè)手機(jī),在訂單完成的界面,網(wǎng)頁會(huì)給你推薦同款手機(jī)的手機(jī)殼,你此時(shí)很可能就會(huì)點(diǎn)進(jìn)去瀏覽一下,順便買一個(gè)手機(jī)殼。

其實(shí)這就是ItemCF算法在背后默默工作。ItemCF算法給用戶推薦那些和他們之前喜歡的物品相似的物品。因?yàn)槟阒百I了手機(jī),ItemCF算法計(jì)算出來手機(jī)殼與手機(jī)之間的相似度較大,所以給你推薦了一個(gè)手機(jī)殼,這就是它的工作原理。

看起來是不是跟UserCF算法很相似是不是?只不過這次不再是計(jì)算用戶之間的相似度,而是換成了計(jì)算物品之間的相似度。

由上述描述可以知道ItemCF算法的主要步驟如下:

計(jì)算物品之間的相似度
根據(jù)物品的相似度和用戶的歷史行為給用戶生成推薦列表
那么擺在我們面前的第一個(gè)問題就是如何計(jì)算物品之間的相似度,這里尤其要特別注意一下:

ItemCF算法并不是直接根據(jù)物品本身的屬性來計(jì)算相似度,而是通過分析用戶的行為來計(jì)算物品之間的相似度。

什么意思呢?比如手機(jī)和手機(jī)殼,除了形狀相似之外沒有什么其它的相似點(diǎn),直接計(jì)算相似度似乎也無從下手。但是換個(gè)角度來考慮這個(gè)問題,如果有很多個(gè)用戶在買了手機(jī)的同時(shí),又買了手機(jī)殼,那是不是可以認(rèn)為手機(jī)和手機(jī)殼比較相似呢vb.net教程C#教程python教程
由此引出物品相似度的計(jì)算公式:






最后將篩選出來的物品按照用戶對其感興趣程度逆序排序,取全體列表或者列表前K個(gè)物品推薦給用戶,至此ItemCF算法完成。

算法工作流程
接下來我們用一個(gè)簡單例子演示一下ItemCF的具體工作流程。

下表是一個(gè)簡易的原始數(shù)據(jù)集,也稱之為User-Item表,即用戶-物品列表,記錄了每個(gè)用戶喜愛的物品,數(shù)據(jù)表格如下:



用戶A的共現(xiàn)矩陣

上圖是用戶A的共現(xiàn)矩陣C,C[i][j]代表的含義是同時(shí)喜歡物品i和物品j的用戶數(shù)量。舉個(gè)例子,C[a][b]=1代表的含義就是同時(shí)喜歡物品a和物品b的用戶有一個(gè),就是用戶A。
由于同時(shí)喜歡物品i和物品j的人與同時(shí)喜歡物品j和物品i的人數(shù)是一樣的,所以這是一個(gè)對稱矩陣。
同樣的道理,其他用戶也都有一張類似的表格。因?yàn)椴煌挠脩舻南矏畚锲妨斜聿灰恢?,?huì)導(dǎo)致每個(gè)用戶形成的共現(xiàn)矩陣大小不一,這里為了統(tǒng)一起見,將矩陣大小擴(kuò)充到nxn,其中n是所有用戶喜歡物品列表的并集的大小。

下面用一張圖來描述如何構(gòu)建完整的共現(xiàn)矩陣:

通過對不同用戶的喜愛物品集合構(gòu)成的共現(xiàn)矩陣進(jìn)行累加,最終得到了上圖中的矩陣C,這其實(shí)就是相似度公式中的分子部分。

這里只是為了演示如何計(jì)算物品整體共現(xiàn)矩陣,實(shí)際在代碼中我們并不會(huì)采用分別為每個(gè)用戶建立一個(gè)共現(xiàn)矩陣再累加的方式。為了加快效率和節(jié)省空間,可以使用python的dict來實(shí)現(xiàn),具體可以參考代碼實(shí)現(xiàn)章節(jié)。

接下來我們計(jì)算最終的物品相似度矩陣,以物品a和物品b的相似度計(jì)算為例,通過上面計(jì)算的計(jì)算可知C[a][b]=1,即同時(shí)喜歡物品a和物品b的用戶有一位。根據(jù)User-Item表可以統(tǒng)計(jì)出N(a)=2,N(b)=3,那么物品a和物品b的相似度計(jì)算如下:

有了物品相似度矩陣W之后,我們對用戶進(jìn)行物品推薦了,下面以給用戶C推薦物品為例,展示一下計(jì)算過程:
可以看到用戶C喜歡的物品列表為{c,d},通過查物品相似度矩陣可知,與物品c相似的有{b,d,e},同理與物品d相似的物品有{a,b,c},故最終給用戶C推薦的物品列表為{a,b,e}(注意這里并不是{a,b,c,d,e},因?yàn)橐サ粲脩鬋喜歡的物品,防止重復(fù)推薦)。接下來分別計(jì)算用戶C對這些物品的感興趣程度。

P(C,a) = W[d][a] = 0.71
P(C,b) = W[c][b] + W[d][b]= 0.67 + 0.58 = 1.25
P(C,e) = W[c][e] = 0.58

故給用戶C的推薦列表是{b,a,e}。

相似度算法改進(jìn)
從前面的討論可以看到,在協(xié)同過濾中兩個(gè)物品產(chǎn)生相似度是因?yàn)樗鼈児餐霈F(xiàn)在很多用戶的興趣列表中。換句話說,每個(gè)用戶的興趣列表都對物品的相似度產(chǎn)生貢獻(xiàn)。那么是不是每個(gè)用戶的貢獻(xiàn)都相同呢?

假設(shè)有這么一個(gè)用戶,他是開書店的,并且買了當(dāng)當(dāng)網(wǎng)上80%的書準(zhǔn)備用來自己賣。那么他的購物車?yán)锇?dāng)當(dāng)網(wǎng)80%的書。假設(shè)當(dāng)當(dāng)網(wǎng)有100萬本書,也就是說他買了80萬本。從前面對ItemCF的討論可以看到,這意味著因?yàn)榇嬖谶@么一個(gè)用戶,有80萬本書兩兩之間就產(chǎn)生了相似 度,也就是說,內(nèi)存里即將誕生一個(gè)80萬乘80萬的稠密矩陣。

John S. Breese在論文1中提出了一個(gè)稱為IUF(Inverse User Frequence),即用戶活躍度對數(shù)的 倒數(shù)的參數(shù),他也認(rèn)為活躍用戶對物品相似度的貢獻(xiàn)應(yīng)該小于不活躍的用戶,他提出應(yīng)該增加IUF 參數(shù)來修正物品相似度的計(jì)算公式:

上述公式對活躍用戶做了一種軟性的懲罰,但是對于很多過于活躍的用戶,比如上面那位買了當(dāng)當(dāng)網(wǎng)80%圖書的用戶,為了避免相似度矩陣過于稠密,我們在實(shí)際計(jì)算中一般直接忽略他的興趣列表,而不將其納入到相似度計(jì)算的數(shù)據(jù)集中。

相似度矩陣歸一化處理
Karypis在研究中發(fā)現(xiàn)如果將ItemCF的相似度矩陣按最大值歸一化,可以提高推薦的準(zhǔn)確率。其研究表明,如果已經(jīng)得到了物品相似度矩陣w,那么可以用如下公式得到歸一化之后的相似度矩陣w’:

實(shí)驗(yàn)表明,歸一化的好處不僅僅在于增強(qiáng)推薦的準(zhǔn)確度,還可以提高推薦的覆蓋率和多樣性。

代碼實(shí)踐
根據(jù)之前的介紹,可知整個(gè)算法流程分為兩個(gè)階段:

訓(xùn)練階段
推薦階段
對于訓(xùn)練階段,可分為以下幾步:

數(shù)據(jù)預(yù)處理,建立User-Item表
建立物品整體共現(xiàn)矩陣
建立物品相似度矩陣
對于推薦階段,可分為以下幾步:

尋找與被推薦用戶喜愛物品集最相似的N個(gè)物品
計(jì)算用戶對這N個(gè)物品的感興趣程序列表并逆序排列
訓(xùn)練階段
數(shù)據(jù)預(yù)處理,建立User-Item表
我們采用MovieLens數(shù)據(jù)集中的ratings.dat文件,因?yàn)檫@里面包含了用戶對電影的評分?jǐn)?shù)據(jù),注意我們忽略掉評分那一欄,將其簡化成用戶喜歡或者不喜歡。只要用戶有參與過評分的電影,無論分值如何,我們都認(rèn)為這部電影是用戶喜歡的。

注意,ratings.dat里面包含了100多萬條評價(jià)數(shù)據(jù),為了減少訓(xùn)練時(shí)間,可以只讀取部分?jǐn)?shù)據(jù),本文讀取了前29415條數(shù)據(jù),即前200個(gè)用戶的評價(jià)數(shù)據(jù)。ratings.dat原始數(shù)據(jù)每行包含了4列,本文中只取了’UserID'、’MovieID'這兩列。

接下來使用以下代碼來讀取數(shù)據(jù)并建立User-Item表:

import random
import pandas as pd

def LoadMovieLensData(filepath, train_rate):
    ratings = pd.read_table(filepath, sep="::", header=None, names=["UserID", "MovieID", "Rating", "TimeStamp"],                            engine='python')
    ratings = ratings[['UserID','MovieID']]
    train = []
    test = []
    random.seed(3)
    for idx, row in ratings.iterrows():
        user = int(row['UserID'])
        item = int(row['MovieID'])
        if random.random() < train_rate:
            train.append([user, item])
        else:
            test.append([user, item])
    return PreProcessData(train), PreProcessData(test)

def PreProcessData(originData):
    """
    建立User-Item表,結(jié)構(gòu)如下:
        {"User1": {MovieID1, MoveID2, MoveID3,...}
         "User2": {MovieID12, MoveID5, MoveID8,...}
         ...
        }
    """
    trainData = dict()
    for user, item in originData:
        trainData.setdefault(user, set())
        trainData[user].add(item)
    return trainData

建立物品整體共現(xiàn)矩陣
這里并沒有采用對每個(gè)用戶都建立共現(xiàn)矩陣再累加的方式,而是直接采用了兩重dict來實(shí)現(xiàn)一個(gè)Matrix,然后在此基礎(chǔ)上直接建立共現(xiàn)矩陣。

def ItemMatrix(trainData, similarity):
    """
    建立物品共現(xiàn)矩陣
    :param trainData: User-Item表 
    :param similarity: 相似度計(jì)算函數(shù)選擇
    :return: 
    """
    N = defaultdict(int)  # 記錄每個(gè)物品的喜愛人數(shù)
    itemSimMatrix = defaultdict(int) # 共現(xiàn)矩陣
    for user, items in trainData.items():
        for i in items:
            itemSimMatrix.setdefault(i, dict())
            N[i] += 1
            for j in items:
                if i == j:
                    continue
                itemSimMatrix[i].setdefault(j, 0)
                if similarity == "cosine":
                    itemSimMatrix[i][j] += 1
                elif similarity == "iuf":
                    itemSimMatrix[i][j] += 1. / math.log1p(len(items) * 1.)
    return itemSimMatrix

建立物品相似度矩陣
這一步是是直接在物品共現(xiàn)矩陣的基礎(chǔ)上除以兩個(gè)物品各自喜愛人數(shù)的乘積,并且包含了數(shù)據(jù)歸一化的處理。

def ItemSimilarityMatrix(ItemMatrix, N, isNorm):
    """
    計(jì)算物品相似度矩陣
    :param ItemMatrix: 
    :param N: 
    :param isNorm: 
    :return: 
    """
    itemSimMatrix = dict()
    for i, related_items in ItemMatrix.items():
        for j, cij in related_items.items():
            # 計(jì)算相似度
            itemSimMatrix[i][j] = cij / math.sqrt(N[i] * N[j])
    # 是否要標(biāo)準(zhǔn)化物品相似度矩陣
    if isNorm:
        for i, relations in itemSimMatrix.items():
            max_num = relations[max(relations, key=relations.get)]
            # 對字典進(jìn)行歸一化操作之后返回新的字典
            itemSimMatrix[i] = {k: v / max_num for k, v in relations.items()}
    return itemSimMatrix

推薦階段

def recommend(trainData, itemSimMatrix, user, N, K):
    """
    :param trainData: User-Item表
    :param itemSimMatrix: 物品相似度矩陣
    :param user: 被推薦的用戶user
    :param N: 推薦的商品個(gè)數(shù)
    :param K: 查找的最相似的用戶個(gè)數(shù)
    :return: 按照user對推薦物品的感興趣程度排序的N個(gè)商品
    """
    recommends = dict()
    # 先獲取user的喜愛物品列表
    items = trainData[user]
    for item in items:
        # 對每個(gè)用戶喜愛物品在物品相似矩陣中找到與其最相似的K個(gè)
        for i, sim in sorted(itemSimMatrix[item].items(), key=itemgetter(1), reverse=True)[:K]:
            if i in items:
                continue  # 如果與user喜愛的物品重復(fù)了,則直接跳過
            recommends.setdefault(i, 0.)
            recommends[i] += sim
    # 根據(jù)被推薦物品的相似度逆序排列,然后推薦前N個(gè)物品給到用戶
    return dict(sorted(recommends.items(), key=itemgetter(1), reverse=True)[:N])

核心代碼
下面的代碼實(shí)現(xiàn)了完整的功能,修改“ratings.dat"文件的路徑之后,可以直接運(yùn)行。

import math
import random
import pandas as pd
from collections import defaultdict
from operator import itemgetter

def LoadMovieLensData(filepath, train_rate):
    ratings = pd.read_table(filepath, sep="::", header=None, names=["UserID", "MovieID", "Rating", "TimeStamp"],                            engine='python')
    ratings = ratings[['UserID','MovieID']]

    train = []
    test = []
    random.seed(3)
    for idx, row in ratings.iterrows():
        user = int(row['UserID'])
        item = int(row['MovieID'])
        if random.random() < train_rate:
            train.append([user, item])
        else:
            test.append([user, item])
    return PreProcessData(train), PreProcessData(test)

def PreProcessData(originData):
    """
    建立User-Item表,結(jié)構(gòu)如下:
        {"User1": {MovieID1, MoveID2, MoveID3,...}
         "User2": {MovieID12, MoveID5, MoveID8,...}
         ...
        }
    """
    trainData = dict()
    for user, item in originData:
        trainData.setdefault(user, set())
        trainData[user].add(item)
    return trainData


class ItemCF(object):
    """ Item based Collaborative Filtering Algorithm Implementation"""
    def __init__(self, trainData, similarity="cosine", norm=True):
        self._trainData = trainData
        
    def similarity(self):
        N = defaultdict(int) #記錄每個(gè)物品的喜愛人數(shù)
        for user, items in self._trainData.items():
            for i in items:
                self._itemSimMatrix.setdefault(i, dict())
                N[i] += 1
                for j in items:
                    if i == j:
                        continue
                    self._itemSimMatrix[i].setdefault(j, 0)
                    if self._similarity == "cosine":
                        self._itemSimMatrix[i][j] += 1
                    elif self._similarity == "iuf":
                        self._itemSimMatrix[i][j] += 1. / math.log1p(len(items) * 1.)
        for i, related_items in self._itemSimMatrix.items():
            for j, cij in related_items.items():
                self._itemSimMatrix[i][j] = cij / math.sqrt(N[i]*N[j])
        # 是否要標(biāo)準(zhǔn)化物品相似度矩陣
        if self._isNorm:
            for i, relations in self._itemSimMatrix.items():
                max_num = relations[max(relations, key=relations.get)]
                # 對字典進(jìn)行歸一化操作之后返回新的字典
                self._itemSimMatrix[i] = {k : v/max_num for k, v in relations.items()}

    def recommend(self, user, N, K):
        """
        :param user: 被推薦的用戶user
        :param N: 推薦的商品個(gè)數(shù)
        :param K: 查找的最相似的用戶個(gè)數(shù)
        :return: 按照user對推薦物品的感興趣程度排序的N個(gè)商品
        """
        recommends = dict()
        # 先獲取user的喜愛物品列表
        items = self._trainData[user]
        for item in items:
            # 對每個(gè)用戶喜愛物品在物品相似矩陣中找到與其最相似的K個(gè)
            for i, sim in sorted(self._itemSimMatrix[item].items(), key=itemgetter(1), reverse=True)[:K]:
                if i in items:
                    continue  # 如果與user喜愛的物品重復(fù)了,則直接跳過
                recommends.setdefault(i, 0.)
                recommends[i] += sim
        # 根據(jù)被推薦物品的相似度逆序排列,然后推薦前N個(gè)物品給到用戶
        return dict(sorted(recommends.items(), key=itemgetter(1), reverse=True)[:N])

if __name__ == "__main__":
    train, test = LoadMovieLensData("../Data/ml-1m/ratings.dat", 0.8)
    print("train data size: %d, test data size: %d" % (len(train), len(test)))
    ItemCF = ItemCF(train, similarity='iuf', norm=True)
    ItemCF.train()

    # 分別對以下4個(gè)用戶進(jìn)行物品推薦
    print(ItemCF.recommend(1, 5, 80))

上述代碼對測試集中前4個(gè)用戶進(jìn)行了電影推薦,對每個(gè)用戶而言,從與他們喜愛電影相似的80部電影中挑選出5部推薦。

輸出結(jié)果是一個(gè)dict,里面包含了給用戶推薦的電影以及用戶對每部電影的感興趣程度,按照逆序排列。

結(jié)果如下:

版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。

原文鏈接:https://blog.csdn.net/m0_59596990/article/details/130459464

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    日韩欧美国产精品中文字幕| 韩国日本欧美国产三级| 老司机精品视频在线免费| 亚洲精品欧美精品一区三区| 千仞雪下面好爽好紧好湿全文| 樱井知香黑人一区二区| 国产精品欧美一级免费| 国产传媒精品视频一区| 韩国激情野战视频在线播放| 亚洲中文字幕剧情在线播放| 国产欧美一区二区另类精品 | 亚洲av专区在线观看| 成年人黄片大全在线观看| 日韩人妻有码一区二区| 人妻巨大乳一二三区麻豆| 中文字日产幕码三区国产| 欧洲自拍偷拍一区二区| 国产av乱了乱了一区二区三区| 亚洲妇女作爱一区二区三区| 欧美大黄片在线免费观看| 国产av一区二区三区麻豆| 成人精品网一区二区三区| 福利一区二区视频在线| 日韩免费av一区二区三区| 亚洲永久一区二区三区在线| 欧美国产日韩在线综合| 日韩不卡一区二区视频| 亚洲第一区二区三区女厕偷拍| 亚洲欧美一二区日韩高清在线| 高清不卡视频在线观看| 午夜精品黄片在线播放| 国产亚洲欧美自拍中文自拍| 激情五月综五月综合网| 欧美一区二区口爆吞精| 91日韩欧美中文字幕| 亚洲中文字幕高清视频在线观看| 女生更色还是男生更色| 亚洲精品中文字幕一二三| 四季av一区二区播放| 日韩欧美国产高清在线| 亚洲综合香蕉在线视频|