基于用户协同过滤算法的思考

基于用户协同过滤算法的思考

本文对借鉴文章进行了学习,发现了一些问题,产生了一些思考,然后基于思考实现了一个matrixChain工具,该工具可以显示批量矩阵情况,像链式一样展示,便于更好的学习文章内容,特别是首次接触矩阵转换和计算的算法。

借鉴文章:Python推荐系统算法实现---------基于用户协同过滤算法

实现工具matrixChain:github地址

问题发现

原文中的预测分部分,应用使用的是加权处理,但是后面发现,原文结果获取的电影推荐没有去掉用户本身的评分电影,也就是说可能重复推荐给我,之前用户已经看过且评过分的电影。

所以,下面的代码中有对该的优化。

复盘思考

在初次看代码时,一些矩阵的引入和转换,自己疯狂print,对学习造成了一些障碍,所以就想着是否有工具可以协助学习,就产生了matrixChain工具。这里简单介绍下使用

# 引入matrixChain
from matrixChain import matrix_chain as mc
mc = mc()  # 创建matrixChain对象
# 添加matrixChain
mc.marix_dict(matrix=your_matrix,matrix_title=your_matrix_title,order_num=matrix_order_num)  
# 函数 marix_dict 参数
# matrix= 预展示的矩阵
# matrix_title= 预展示矩阵的标题
# order_num= 预展示矩阵在展示链中的顺序
mc.machain_run()  # 运行matrixChain主函数

代码优化

这里基于上面借鉴文章,因此数据录入,可以去借鉴文章中获取,不再进行搬运了。

而且,由于原文代码更简洁,是基于函数对象进行码文,但是这种对初学者有些障碍,所以下面对此展开了,便于顺序执行和结果分析。

最后,加入了matrixChain工具,可以初步理解和后面复盘使用。

# -*- coding:utf-8 -*-
"""
-- Time: 2025/01/03 9:36
-- Title: userBaseRs.py
-- Software: PyCharm
-- 基于用户的协同过滤推荐算法(基于皮尔逊相关度)
"""
from matrixChain import matrix_chain as mc
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
# 堆排序模块
import heapq

mc = mc()  # 创建matrixChain对象

# 一、数据录入
# 1.用户评分数据
df = pd.read_csv(r'./data/ml-100k/u.data', sep='\t', names=['user_id', 'item_id', 'rating', 'titmestamp'])
df.head()

# 2.电影数据 电影标题
movie_titles = pd.read_csv(r'./data/ml-100k/u.item', sep='|', encoding='ISO-8859-1', header=None)
movie_titles.rename(columns = {0: "item_id", 1: "title"},  inplace=True)
movie_titles.head()

# 3.合并数据
df1 = pd.merge(df, movie_titles[['item_id','title']], on='item_id')
df1.head()
mc.marix_dict(matrix=df1.to_numpy(),matrix_title="原始矩阵",order_num=1)  # 添加matrixChain

# 二、数据处理
# 4.评分标准化
df1['rating'] = (df1['rating'] - df1['rating'].min()) / (df1['rating'].max() - df1['rating'].min())

# 5.将数据透视为一个表格:index行索引、columns列索引、values要透视的值
user_matrix1 = df1.pivot_table(index='user_id', columns='title', values='rating')
mc.marix_dict(matrix=user_matrix1.to_numpy(),matrix_title="透视矩阵",order_num=2)  # 添加matrixChain
# 6.返回电影标题数组
title = user_matrix1.columns

# 7.生成"用户-电影"关于评分的矩阵m*n
m = df1['user_id'].max()  # 用户最大数量,考虑id从0开始,所有+1 943
n = df1['item_id'].max()  # 电影最大数量  1682
df1.sort_values(by=['user_id', 'item_id'], inplace=True)
user_matrix_num = np.zeros((m, n))
for line in df1.itertuples():
    # 0矩阵 赋值 矩阵索引从0开始所以-1 line[1]是user_id、line[2]是item_id、line[3]是rating
    user_matrix_num[int(line[1]) - 1, int(line[2]) - 1] = line[3]
mc.marix_dict(matrix=user_matrix_num,matrix_title="用户评分矩阵",order_num=3)  # 添加matrixChain

# 三、计算用户之间的皮尔逊相关度
# 8.相关度计算(皮尔逊)并对缺失值进行填充和将其转换为numpy数组,用户两两之间的相关度
user_pearson = pd.DataFrame(user_matrix_num).T.corr(method='pearson')
user_pearson = user_pearson.fillna(0)
user_pearson_num = user_pearson.to_numpy()
mc.marix_dict(matrix=user_pearson_num,matrix_title="皮尔逊矩阵",order_num=4)  # 添加matrixChain
# 四、推荐分预测 -使用加权求和法
# 9.首先,创建评分记录矩阵record,含有评分记录为1,否则为0 即筛选
record = user_matrix_num > 0  # 出来为布尔值
record = np.array(record, dtype=int)  # 布尔值转为整型 943 1682
mc.marix_dict(matrix=record,matrix_title="评分布尔矩阵",order_num=5)  # 添加matrixChain
#   然后,创建用户对所评电影的平均评分矩阵
mean_user_rating = np.zeros((m, 1))  # 用户每部电影的平均得分 m=943
for i in range(m):
    idx = record[i, :] != 0  # 用户i对每部电影的是否评分,[i,:]表示每一行的所有列
    # 平均评分矩阵结合"用户-电影"评分矩阵,只取用户i对电影已评分的行记录矩阵,计算平均然后赋值给平均评分矩阵
    mean_user_rating[i] = np.mean(user_matrix_num[i, idx])  # 第i行,用户i对已评分电影的平均得分
#   接着,获得减去平均得分后得"用户-电影"评分矩阵,即"用户-电影"评分去均矩阵
ratings_diff = (user_matrix_num - mean_user_rating)  # 列中每一个元素减去平均数0
mc.marix_dict(matrix=ratings_diff,matrix_title="去均评分矩阵",order_num=6)  # 添加matrixChain
# 计算推荐结果:[皮尔逊系数矩阵(矩阵乘)"用户-电影"评分去均矩阵的结果矩阵]比上[(皮尔逊系绝对值矩阵按照行求和)转置结果矩阵],然后加上用户电影评分均值
# 获得预测推荐分矩阵:使用加权求和法
user_prediction = mean_user_rating + user_pearson_num.dot(ratings_diff) / np.array([np.abs(user_pearson_num).sum(axis=0)]).T
mc.marix_dict(matrix=user_prediction,matrix_title="预测矩阵",order_num=7)  # 添加matrixChain
mc.machain_run()  # 运行matrixChain

# 10.命令行循环交互
while True:
    userid = int(input("请输入用户id(如:3):"))
    while userid not in range(0, 944):  # 考虑id从1开始,所有+1
        userid = int(input("抱歉您输入的用户id不存在:"))
    if userid == 0:
        print("感谢使用")
        break
    # 用户推荐十个
    n = 10
    # 这里利用record矩阵,对已经已经评过分(认为已经看过了)的电影,乘以一个比较大的负数,比如-1000,这样后面排序会过滤掉
    a1 = user_prediction[userid-1, :]  # 因为上面+1,这里复原-1
    a = record[userid-1, :]*(-1000) + a1
    # 堆排序 在数据集中找到最大的N个,这里用于指定排序的函数为 a.take,返回内容为range(len(a))
    max_indexs = heapq.nlargest(n, range(len(a)), a.take)
    print('已为用户id为{}用户推荐以下十部电影:'.format(userid))
    k = 0
    for i in max_indexs:
        k = k + 1
        print('{}.{},推荐值为:{}'.format(k, title[i], user_prediction[userid-1, :][i]))
    print()

工具效果展示

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值