基於用戶的協同過濾算法(UserCF)

用戶相似度計算

協同過濾算法主要利用行爲的相似度計算興趣的相似度。給定用戶 u 和用戶v ,令 N(u) 表示用戶 u 感興趣的物品集合,令 N(v)爲用戶 v感興趣的物品集合。那麼我們可以通過 Jaccard 公式或者餘弦公式來計算用戶 u, v的相似程度:


 

假設目前共有4個用戶:ABCD;共有5個漫威英雄人物:死侍、鋼鐵俠、美國隊長、黑豹、蜘蛛俠。用戶與人物之間的愛好程度如下圖所示:

 

建立物品到用戶的倒排表,對於每個物品都保存對該物品產生過行爲的用戶列表。倒排表爲喜歡每個物品對應的用戶,如下所示:

假設用戶 A和用戶 B 同時屬於倒排表中K 個人物對應的用戶列表,就有 C[A][B]=K。從而,可以掃描倒排表中每個物品對應的用戶列表,將用戶列表中的兩兩用戶對應的 C[A][B]加1,最終就可以得到所有用戶之間不爲0的稀疏矩陣 C[A][B]

用戶相似度改進

如果兩個用戶都喜歡同一個物品,但這不能說明他們興趣一定相似,比如我們小學的時候基本買過《新華字典》,但是是我們都對這個感興趣。但如果兩個用戶都買過《python數據分析與挖掘實戰》,那可以認爲他們的興趣比較相似,因爲只有研究數據挖掘的人才會買這本書。所以換句話說,兩個用戶對冷門物品採取過同樣的行爲更能說明他們興趣的相似度。因此又提出瞭如下公式,根據用戶行爲計算用戶的興趣相似度:

分子中的倒數懲罰了用戶u和用戶v共同興趣列表中熱門物品對他們相似度的影響。N(i)是對物品i有過行爲的用戶集合,越熱門,N(i)越大,懲罰越大。

推薦

w(uv)爲用戶u與用戶v的相似度,r(vi)爲用戶v對商品i的打分

python實現

import math


class UserCF:
    def __init__(self):
        self.user_score_dict = self.initUserScore()
        # self.users_sim = self.userSimilarity()
        # self.users_sim = self.userSimilarityBetter()
        self.users_sim = self.UserSimilarityBest()

    # 初始化用戶評分數據
    def initUserScore(self):
        user_score_dict = {"A": {"a": 3.0, "b": 4.0, "c": 0.0, "d": 3.5, "e": 0.0},
                           "B": {"a": 4.0, "b": 0.0, "c": 4.5, "d": 0.0, "e": 3.5},
                           "C": {"a": 0.0, "b": 3.5, "c": 0.0, "d": 0., "e": 3.0},
                           "D": {"a": 0.0, "b": 4.0, "c": 0.0, "d": 3.50, "e": 3.0}}
        return user_score_dict

    # 計算用戶之間的相似度,採用的是遍歷每一個用戶進行計算
    def userSimilarity(self):
        W = dict()
        for u in self.user_score_dict.keys():
            W.setdefault(u, {})
            for v in self.user_score_dict.keys():
                if u == v:
                    continue
                u_set = set([key for key in self.user_score_dict[u].keys() if self.user_score_dict[u][key] > 0])
                v_set = set([key for key in self.user_score_dict[v].keys() if self.user_score_dict[v][key] > 0])
                W[u][v] = float(len(u_set & v_set)) / math.sqrt(len(u_set) * len(v_set))
        return W

    # 計算用戶之間的相似度,採用優化算法時間複雜度的方法
    def userSimilarityBetter(self):
        # 得到每個item被哪些user評價過
        item_users = dict()
        for u, items in self.user_score_dict.items():
            for i in items.keys():
                item_users.setdefault(i, set())
                if self.user_score_dict[u][i] > 0:
                    item_users[i].add(u)
        # 構建倒排表
        C = dict()
        N = dict()
        for i, users in item_users.items():
            for u in users:
                N.setdefault(u, 0)
                N[u] += 1  # 每個商品下用戶出現一次就加一次,就是計算每個用戶一共購買的商品個數。
                C.setdefault(u, {})
                for v in users:
                    C[u].setdefault(v, 0)
                    if u == v:
                        continue
                    C[u][v] += 1
        print(C)
        print(N)
        # 構建相似度矩陣
        W = dict()
        for u, related_users in C.items():
            W.setdefault(u, {})
            for v, cuv in related_users.items():
                if u == v:
                    continue
                W[u].setdefault(v, 0.0)
                W[u][v] = cuv / math.sqrt(N[u] * N[v])
        return W

    # 計算用戶之間的相似度,採用懲罰熱門商品和優化算法複雜度的算法
    def UserSimilarityBest(self):
        # 得到每個item被哪些user評價過
        item_users = dict()
        for u, items in self.user_score_dict.items():
            for i in items.keys():
                item_users.setdefault(i, set())
                if self.user_score_dict[u][i] > 0:
                    item_users[i].add(u)
        # 構建倒排表
        C = dict()
        N = dict()
        for i, users in item_users.items():
            for u in users:
                N.setdefault(u, 0)
                N[u] += 1
                C.setdefault(u, {})
                for v in users:
                    C[u].setdefault(v, 0)
                    if u == v:
                        continue
                    C[u][v] += 1 / math.log(1 + len(users))
        # 構建相似度矩陣
        W = dict()
        for u, related_users in C.items():
            W.setdefault(u, {})
            for v, cuv in related_users.items():
                if u == v:
                    continue
                W[u].setdefault(v, 0.0)
                W[u][v] = cuv / math.sqrt(N[u] * N[v])
        return W

    # 預測用戶對item的評分
    def preUserItemScore(self, userA, item):
        score = 0.0
        for user in self.users_sim[userA].keys():
            if user != userA:
                score += self.users_sim[userA][user] * self.user_score_dict[user][item]
        return score

    # 爲用戶推薦物品
    def recommend(self, userA):
        # 計算userA 未評分item的可能評分
        user_item_score_dict = dict()
        for item in self.user_score_dict[userA].keys():
            if self.user_score_dict[userA][item] <= 0:
                user_item_score_dict[item] = self.preUserItemScore(userA, item)
        return user_item_score_dict


if __name__ == "__main__":
    ub = UserCF()
    print(ub.recommend("C"))

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章