协同过滤推荐算法原理及Python实现

协同过滤推荐算法(Collaborative Filtering, CF)是一种常见的推荐系统技术,其核心思想是通过分析用户的行为和偏好,发现用户或物品之间的相似性,从而为用户推荐他们可能感兴趣的物品。这种算法在电商、社交媒体、视频和音乐平台等各个领域都有广泛应用。

协同过滤推荐算法基于一个假设:如果用户之间在兴趣上相似,那么他们在未来可能喜欢的物品上也会有共同的喜好。该算法通过分析用户对物品的评分、购买、浏览等行为数据,发现用户或物品之间的潜在联系,进而实现个性化推荐。

协同过滤推荐算法主要分为两种类型:基于用户的协同过滤(User-Based Collaborative Filtering)和基于物品的协同过滤(Item-Based Collaborative Filtering)。

  1. 基于用户的协同过滤
    • 原理:通过分析不同用户之间的相似性,找到与目标用户相似的其他用户,然后根据这些相似用户的行为和评分来预测目标用户对未评分物品的兴趣程度,并生成推荐列表。
    • 实现步骤
      1. 计算用户之间的相似度,常用的相似度计算方法包括余弦相似度、皮尔逊相关系数等。
      2. 根据相似度选择与目标用户最相似的K个用户(K近邻算法)。
      3. 利用这些相似用户对物品的评分来预测目标用户对未评分物品的兴趣程度。
  2. 基于物品的协同过滤
    • 原理:通过分析不同物品之间的相似性,找到与目标物品相似的其他物品,然后根据用户对相似物品的评分来预测其对未评分物品的兴趣程度。
    • 实现步骤
      1. 计算物品之间的相似度,常用的相似度计算方法包括余弦相似度、杰卡德相似度等。
      2. 根据相似度选择与目标物品最相似的K个物品。
      3. 利用用户对这些相似物品的评分来预测其对未评分物品的兴趣程度

 

# coding = utf-8

# 推荐算法实现
import csv
import random

import pymysql
import math
from operator import itemgetter


class UserBasedCF():
    # 初始化相关参数
    def __init__(self):
        # 找到与目标用户兴趣相似的3个用户,为其推荐5个商品
        self.n_sim_user = 3
        self.n_rec_product = 5

        self.dataSet = {}

        # 将数据集划分为训练集和测试集
        self.trainSet = {}
        self.testSet = {}

        # 用户相似度矩阵
        self.user_sim_matrix = {}
        self.product_count = 0

        print('Similar user number = %d' % self.n_sim_user)
        print('Recommneded product number = %d' % self.n_rec_product)


    # 读文件得到“用户-商品”数据
    def get_dataset(self, filename, pivot=0.75):
        dataSet_len = 0
        trainSet_len = 0
        testSet_len = 0
        for line in self.load_file(filename):
            user, product, rating = line.split(',')
            # if random.random() < pivot:
            self.dataSet.setdefault(user, {})
            self.dataSet[user][product] = rating
            dataSet_len += 1
            if(random.random() < pivot):
                self.trainSet.setdefault(user, {})
                self.trainSet[user][product] = rating
                trainSet_len += 1
            else:
                self.testSet.setdefault(user, {})
                self.testSet[user][product] = rating
                testSet_len += 1
            # else:
            #     self.testSet.setdefault(user, {})
            #     self.testSet[user][product] = rating
            #     testSet_len += 1
        print('Split trainingSet and testSet success!')
        print('dataSet = %s' % dataSet_len)
        print('TrainSet = %s' % trainSet_len)
        print('TestSet = %s' % testSet_len)


    # 读文件,返回文件的每一行
    def load_file(self, filename):
        with open(filename, 'r') as f:
            for i, line in enumerate(f):
                if i == 0:  # 去掉文件第一行的title
                    continue
                yield line.strip('\r\n')
        print('Load %s success!' % filename)


    # 计算用户之间的相似度
    def calc_user_sim(self):
        # 构建“商品-用户”倒排索引
        # key = productID, value = list of userIDs who have seen this product
        print('Building product-user table ...')
        product_user = {}
        for user, products in self.trainSet.items():
            for product in products:
                if product not in product_user:
                    product_user[product] = set()
                product_user[product].add(user)
        print('Build product-user table success!')

        self.product_count = len(product_user)
        print('Total product number = %d' % self.product_count)

        print('Build user co-rated products matrix ...')
        for product, users in product_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
        print('Build user co-rated products matrix success!')

        # 计算相似性
        print('Calculating user similarity matrix ...')
        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.trainSet[u]) * len(self.trainSet[v]))
        print('Calculate user similarity matrix success!')


    # 针对目标用户U,找到其最相似的K个用户,产生N个推荐
    def recommend(self, user):
        K = self.n_sim_user
        N = self.n_rec_product
        rank = {}
        watched_products = self.trainSet[user]

        # v=similar user, wuv=similar factor
        for v, wuv in sorted(self.user_sim_matrix[user].items(), key=itemgetter(1), reverse=True)[0:K]:
            for product in self.trainSet[v]:
                if product in watched_products:
                    continue
                rank.setdefault(product, 0)
                rank[product] += wuv
        return sorted(rank.items(), key=itemgetter(1), reverse=True)[0:N]


    # 产生推荐并通过准确率、召回率和覆盖率进行评估
    def evaluate(self):
        print("Evaluation start ...")
        N = self.n_rec_product
        # 准确率和召回率
        hit = 0
        rec_count = 0
        test_count = 0
        # 覆盖率
        all_rec_products = set()

        # 打开数据库连接
        db = pymysql.connect(host='localhost', user='root', password='123456', database='movie', charset='utf8')
        cursor = db.cursor()
        # 使用 execute()  方法执行 SQL 查询
        sql1="truncate table rec;"
        cursor.execute(sql1)
        db.commit()
        sql = "insert into rec(user_id,movie_id,rating ) values (%s,%s,%s)"

        for i, user, in enumerate(self.trainSet):
            test_moives = self.testSet.get(user, {})
            rec_products = self.recommend(user)
            print(user,rec_products)
            for item in rec_products:
                data=(user,item[0],item[1])
                if item[0] in test_moives:
                    hit += 1
                cursor.execute(sql, data)
            rec_count += N
            test_count += len(test_moives)
            db.commit()
            #rec_products 是推荐后的数据
            #把user-rec-rating 存到数据库
        cursor.close()
        db.close()

        precision = hit / (1.0 * rec_count)
        recall = hit / (1.0 * test_count)
        coverage = len(all_rec_products) / (1.0 * self.product_count)
        print('precisioin=%.4f\trecall=%.4f\tcoverage=%.4f' % (precision, recall, coverage))


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_892532969

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值