小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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






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

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

下表是一個(gè)簡(jiǎn)易的原始數(shù)據(jù)集,也稱之為User-Item表,即用戶-物品列表,記錄了每個(gè)用戶喜愛(ài)的物品,數(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è)對(duì)稱矩陣。
同樣的道理,其他用戶也都有一張類似的表格。因?yàn)椴煌挠脩舻南矏?ài)物品列表不一致,會(huì)導(dǎo)致每個(gè)用戶形成的共現(xiàn)矩陣大小不一,這里為了統(tǒng)一起見,將矩陣大小擴(kuò)充到nxn,其中n是所有用戶喜歡物品列表的并集的大小。

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

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

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

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

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é)同過(guò)濾中兩個(gè)物品產(chǎn)生相似度是因?yàn)樗鼈児餐霈F(xiàn)在很多用戶的興趣列表中。換句話說(shuō),每個(gè)用戶的興趣列表都對(duì)物品的相似度產(chǎn)生貢獻(xiàn)。那么是不是每個(gè)用戶的貢獻(xiàn)都相同呢?

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

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

上述公式對(duì)活躍用戶做了一種軟性的懲罰,但是對(duì)于很多過(guò)于活躍的用戶,比如上面那位買了當(dāng)當(dāng)網(wǎng)80%圖書的用戶,為了避免相似度矩陣過(guò)于稠密,我們?cè)趯?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)練階段
推薦階段
對(duì)于訓(xùn)練階段,可分為以下幾步:

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

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

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

接下來(lái)使用以下代碼來(lái)讀取數(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)矩陣
這里并沒(méi)有采用對(duì)每個(gè)用戶都建立共現(xiàn)矩陣再累加的方式,而是直接采用了兩重dict來(lái)實(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è)物品的喜愛(ài)人數(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è)物品各自喜愛(ài)人數(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)]
            # 對(duì)字典進(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對(duì)推薦物品的感興趣程度排序的N個(gè)商品
    """
    recommends = dict()
    # 先獲取user的喜愛(ài)物品列表
    items = trainData[user]
    for item in items:
        # 對(duì)每個(gè)用戶喜愛(ài)物品在物品相似矩陣中找到與其最相似的K個(gè)
        for i, sim in sorted(itemSimMatrix[item].items(), key=itemgetter(1), reverse=True)[:K]:
            if i in items:
                continue  # 如果與user喜愛(ài)的物品重復(fù)了,則直接跳過(guò)
            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è)物品的喜愛(ài)人數(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)]
                # 對(duì)字典進(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對(duì)推薦物品的感興趣程度排序的N個(gè)商品
        """
        recommends = dict()
        # 先獲取user的喜愛(ài)物品列表
        items = self._trainData[user]
        for item in items:
            # 對(duì)每個(gè)用戶喜愛(ài)物品在物品相似矩陣中找到與其最相似的K個(gè)
            for i, sim in sorted(self._itemSimMatrix[item].items(), key=itemgetter(1), reverse=True)[:K]:
                if i in items:
                    continue  # 如果與user喜愛(ài)的物品重復(fù)了,則直接跳過(guò)
                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()

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

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

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

結(jié)果如下:

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

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

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多