矩阵分解(Matrix Factorization)

  • 矩阵分解基本原理
  • 用户矩阵U与物品矩阵V求解
  • 矩阵分解详解好文
  • 实现矩阵分解Python代码
    • 参考

矩阵分解基本原理

将mn维的共现矩阵R分解为mk维的用户矩阵U和k*n维的物品矩阵V相乘的形式。其中m是用户数量,n是物品数量,k是隐向量维度。k的大小决定了隐向量表达能力的强弱。k取值越小,隐向量的表达能力就越弱;反之,k取值越大,隐向量表达能力越强
实例:

基于用户矩阵U和物品矩阵V,用户u对物品i的预估评分为:
r^ui=qiTpu\hat{r}_{ui}=q_{i}^{T}p_{u}r^ui​=qiT​pu​
参数说明:
qi:物品i的隐向量
pu:用户u的隐向量

用户矩阵U与物品矩阵V求解

矩阵分解详解好文

这是一篇讲解矩阵分解非常详细的博文,放在这里,便于日后自己多读几遍,全面深入理解矩阵分解算法
基于矩阵分解的推荐算法

实现矩阵分解Python代码

程序亲测有效,程序中附有详细说明

import numpy as np
import pandas as pd
import os
import time
import math'''
说明: 使用的数据集 MovieLens 100K
数据集下载地址: https://grouplens.org/datasets/movielens/100k/
''''''
参数说明:R:用户-物品对应的共现矩阵 m*nP:用户因子矩阵 m*kQ:物品因子矩阵 k*nK:隐向量的维度 steps:最大迭代次数alpha:学习率Lambda:L2正则化的权重系数
'''# 将矩阵R分解成P,Q
def matrix_factorization(R, P, Q, K, steps, alpha=0.05, Lambda=0.002):# 总时长sum_st = 0# 前一次的损失大小e_old = 0# 程序结束的标识flag = 1# 梯度下降结束条件1:满足最大迭代次数for step in range(steps):# 每次跌代开始的时间st = time.time()cnt = 0e_new = 0for u in range(1, len(R)):for i in range(1, len(R[u])):if R[u][i] > 0:eui = R[u][i] - np.dot(P[u, :], Q[:, i])for k in range(K):temp = P[u][k]P[u][k] = P[u][k] + alpha * eui * Q[k][i] - Lambda * P[u][k]Q[k][i] = Q[k][i] + alpha * eui * temp - Lambda * Q[k][i]for u in range(1, len(R)):for i in range(1, len(R[u])):if R[u][i] > 0:cnt += 1e_new = e_new + pow(R[u][i] - np.dot(P[u, :], Q[:, i]), 2)e_new = e_new / cntet = time.time()sum_st = sum_st + (et - st)# 第一次迭代不执行前后损失之差if step == 0:e_old = e_newcontinue# 梯度下降结束条件2:loss过小,跳出if e_new < 1e-3:flag = 2break# 梯度下降结束条件3:前后loss之差过小,跳出if (e_old - e_new) < 1e-10:flag = 3breakelse:e_old = e_newprint(f'--------Summary---------\nThe type of jump out:{flag}\nTotal steps:{step+1}\nTotal time:{sum_st}\n'f'Average time:{sum_st / (step+1)}\nThe e is :{e_new}')return P, Q#查看数据内容
def view_data():rtnames = ['user', 'item', 'score', 'time']data = pd.read_csv("D:\\YSA\\MovieLens\\ml-100k\\ML100K.txt", sep='\t', header=None, names=rtnames)# print(data.head())# 用户数量u_cnt = len(np.unique(data[rtnames[0]]))# 项目数量i_cnt = len(np.unique(data['item']))# 记录数量r_cnt = len(data)# 用户最小访问项目数量u_cnt_min = min(data['user'].value_counts().values)# 用户平均访问项目数量u_cnt_avg = r_cnt / u_cnt# 项目最小被访问量i_cnt_min = min(data['item'].value_counts().values)# 项目平均被访问量i_cnt_avg = r_cnt / i_cnt# 分割数据集成训练集、测试集
def split_data(dformat):# 读取原始数据rating = pd.read_csv("D:\\YSA\\MovieLens\\ml-100k\\ML100K.txt", sep='\t', header=None, names=dformat)# 按照时间顺序排序rating.sort_values(by=['time'], axis=0, inplace=True)# 按照时间顺序值8:2,确定边界线boundary = rating['time'].quantile(0.8)# 按时间分界点切分数据,生成训练集train = rating[rating['time'] < boundary]# 训练集按用户、时间顺序排序train.sort_values(by=['user', 'time'], axis=0, inplace=True)# 按时间分界点切分数据,生成测试集test = rating[rating['time'] >= boundary]# 测试集按用户、时间顺序排序test.sort_values(by=['usr', 'time'], axis=0, inplace=True)data = pd.concat([train, test])# 确认目录是否存在if os.path.exists("D:\\YSA\\MovieLens\\ml-100k"):passelse:os.mkdir("D:\\YSA\\MovieLens\\ml-100k")# 将训练集、测试集写入文件中train.to_csv("D:\\YSA\\MovieLens\\ml-100k\\ML100K_Train.txt", sep=',', index=False, header=None)test.to_csv("D:\\YSA\\MovieLens\\ml-100k\\ML100K_test.txt", sep=',', index=False, header=None)print(f'split data complete!')# 获取本地数据
def getData(path, dformat):# 读取用户-共现矩阵数据rating = np.loadtxt(path+"\\Basic_MF\\rating.txt", delimiter=',', dtype=float)# 读取训练集数据trainData = pd.read_csv(path+"\\ML100K_Train.txt", sep=',', header=None, names=dformat)# 读取测试集数据testData = pd.read_csv(path+"\\ML100K_test.txt", sep=',', header=None, names=dformat)data = pd.concat([trainData, testData])# 总用户数量all_user = np.unique(data['user'])# 总项目数量all_item = np.unique(data['item'])return rating, trainData, testData, all_user, all_item# 生成用户-物品矩阵并保存到本地文件中
def getUserItem(path, train, all_user, all_item):train.sort_values(by=['user, item'], axis=0, inplace=True)# 用户-项目共现矩阵行数num_user = len(all_user)+1# 用户-项目共现矩阵列数num_item = len(all_item)+1# 用户-项目共现矩阵初始化rating_mat = np.zeros([num_user, num_item], dtype=int)# 用户-项目共现矩阵赋值for i in range(len(train)):user = train.iloc[i]['user']item = train.iloc[i]['item']score = train.iloc[i]['score']rating_mat[user][item] = score# 判断文件夹是否存在if os.path.exists(path+"\\BasicMF"):passelse:os.mkdir(path+"\\BasicMF")# 保存用户-项目共现矩阵到文件np.savetxt(path+"\\BasicMF\\rating.txt", rating_mat, fmt='%d', delimiter=',', newline='\n')print(f'generate rating matrix complete!')#  训练
def train(path, rating, K, steps):R = ratingM = len(R)N = len(R[0])# 用户矩阵初始化P = np.random.normal(loc=0, scale=0.01, size=(M, K))# 项目矩阵初始化Q = np.random.normal(loc=0, scale=0.01, size=(K, N))P, Q = matrix_factorization_BiasSVD(R, P, Q, K, steps)# 判断文件夹是否存在if os.path.exists(path + "\\Basic_MF"):passelse:os.mkdir(path + "\\Basic_MF")# 将P,Q保存到文件np.savetxt(path+"\\Basic_MF\\userMatrix.txt", P, fmt="%.6f", delimiter=',', newline='\n')np.savetxt(path+"\\Basic_MF\\itemMatrix.txt", Q, fmt="%.6f", delimiter=',', newline='\n')print("train complete!")# 生成topk推荐列表
def topK(dic, k):keys = []values = []for i in range(k):key, value = max(dic.items(), key=lambda x: x[1])keys.append(key)values.append(value)dic.pop(key)return keys, values# 测试
def test(path, trainData, testData, all_item, k):# 读取用户矩阵P = np.loadtxt(path+"\\Basic_MF\\userMatrix.txt", delimiter=',', dtype=float)# 读取项目矩阵Q = np.loadtxt(path+"\\Basic_MF\\itemMatrix.txt", delimiter=',', dtype=float)# 测试集中的用户集合testUser = np.unique(testData['user'])# 测试集的长度test_lenght = len(testData)Hits = 0MRR = 0NDCG= 0# 开始时间st = time.time()for user_i in testUser:# 测试集第i个用户在训练集已访问的项目visited_list = list(trainData[trainData['user'] == user_i]['item'])# 没有训练数据,跳过if len(visited_list) == 0:continue# 测试集第i个用户的访问项目并去重test_list = list(testData[testData['user'] == user_i]['item'].drop_duplicates())# 测试集第i个用户的访问项目中去除该用户在训练集已访问的项目test_list = list(set(test_list) - set(test_list).intersection(set(visited_list)))# 测试集第i个用户的访问项目为空,跳过if len(test_list) == 0:continue# 生成测试集第i个用户未访问的项目:评分对poss = {}for item in all_item:if item in visited_list:continueelse:poss[item] = np.dot(P[user_i, :], Q[:, item])# 生成测试集第i个用户的推荐列表ranked_list, test_score = topK(poss, k)# 命中测试集第i个用户访问项目的列表h = list(set(test_list).intersection(set(ranked_list)))Hits += len(h)for item in test_list:for i in range(len(ranked_list)):if item == ranked_list[i]:MRR += 1 / (i+1)NDCG += 1 / (math.log2(i+1+1))else:continueHR = Hits / test_lenghtMRR /= test_lenghtNDCG /= test_lenght# 结束时间et = time.time()print("HR@10:%.4f\nMRR@10:%.4f\nNDCG@10:%.4f\nTotal time:%.4f" % (HR, MRR, NDCG, et-st))if __name__ == '__main__':rtnames = ['user', 'item', 'score', 'time']path = "D:\\YSA\\MovieLens\\ml-100k"rating, trainData, testData, all_user, all_item = getData(path, rtnames)# train(path, rating, 30, 10)test(path, trainData, testData, all_item, 10)

参考

1.https://blog.csdn.net/qq_34862636/article/details/105432139

推荐系统之矩阵分解MF原理及Python实现相关推荐

  1. 推荐系统入门(三):矩阵分解MF因子分解机FM(附代码)

    推荐系统入门(三):矩阵分解MF&因子分解机FM(附代码) 目录 推荐系统入门(三):矩阵分解MF&因子分解机FM(附代码) 一. 矩阵分解MF 1. 隐含语义分析技术 1.1 隐语义 ...

  2. 原理篇 | 推荐系统之矩阵分解模型

    导语:本系列文章一共有三篇,分别是 <科普篇 | 推荐系统之矩阵分解模型> <原理篇 | 推荐系统之矩阵分解模型> <实践篇 | 推荐系统之矩阵分解模型> 第一篇用 ...

  3. 【原理篇】推荐系统之矩阵分解模型

    导语: 上次给大家分享了本系列文章第一篇<[科普篇]推荐系统之矩阵分解模型>,第一篇用一个具体的例子介绍了MF是如何做推荐的.今天给大家带来第二篇<[原理篇]推荐系统之矩阵分解模型& ...

  4. 推荐系统——3、原理篇 | 推荐系统之矩阵分解模型

    上一篇我们用一个简单的例子讲述了矩阵分解(Matrix Factorization, MF)是如何做推荐的,但没有深入到算法的细节.如果想编写自己的代码实现MF,那么就需要了解其中的细节了.本文是MF ...

  5. 推荐系统之矩阵分解和FM

    推荐系统之矩阵分解和FM 一.矩阵分解 1. 隐语义模型与矩阵分解 2. 隐语义模型 3. 矩阵分解算法的原理 4. 矩阵分解算法的求解 5. Basic SVD 6. 编程实现 7. 课后思考 8. ...

  6. 实践篇 | 推荐系统之矩阵分解模型

    导语:本系列文章一共有三篇,分别是 <科普篇 | 推荐系统之矩阵分解模型> <原理篇 | 推荐系统之矩阵分解模型> <实践篇 | 推荐系统之矩阵分解模型> 第一篇用 ...

  7. 科普篇 | 推荐系统之矩阵分解模型

    导语:本系列文章一共有三篇,分别是 <科普篇 | 推荐系统之矩阵分解模型> <原理篇 | 推荐系统之矩阵分解模型> <实践篇 | 推荐系统之矩阵分解模型> 第一篇用 ...

  8. 【实践篇】推荐系统之矩阵分解模型-腾讯技术

    导语:本系列文章一共有三篇,分别是 <科普篇 | 推荐系统之矩阵分解模型> <原理篇 | 推荐系统之矩阵分解模型> <实践篇 | 推荐系统之矩阵分解模型> 第一篇用 ...

  9. python实现推荐系统代码_推荐系统之矩阵分解及其Python代码实现

    有如下R(5,4)的打分矩阵:("-"表示用户没有打分) 其中打分矩阵R(n,m)是n行和m列,n表示user个数,m行表示item个数 那么,如何根据目前的矩阵R(5,4)如何对 ...

最新文章

  1. java遍历查询的某一列_【jQuery:遍历相同class的所有值,遍历某一列td的值】
  2. Centos源码安装Cmake
  3. HUST 1600 Lucky Numbers
  4. iOS总结:项目中的各种小坑汇总
  5. 应用DOM操作文档的一个实用例子
  6. Kotlin实战指南八:高阶函数
  7. 常见DDoS技术方法和对应防御措施
  8. TensorFlow发布全新版本,又会带来哪些变革?
  9. java 配置jmstemplate_Spring JMSTemplate 与 JMS 原生API比较
  10. VC 系统托盘 气泡提示
  11. fclose在c语言中的作用,c语言fcloseall函数用法实例介绍
  12. Google Wave 的失败给现代实时协作办公的一个重大教训!
  13. 基于vue-cli3+typescript+element-ui搭建起来的后端管理平台框架(骨架)
  14. 移动端html头部meta标签的含义
  15. 匿名电子邮件转发系统
  16. mir2 client: review
  17. android wifi音箱,(原创)图文并茂教程,手把手教你用安卓手机当电脑的无线扬声器(喇叭)...
  18. 机器人中的yaw/pitch/roll
  19. “马里奥(Mario)之父”──宫本茂
  20. 等额本金计算公式解析

热门文章

  1. 2万字系统总结,帮你实现 Linux 命令自由
  2. 三步教你多行公式将公式编号垂直居中
  3. 关于iPhone屏幕尺寸、分辨率及适配
  4. 创建你的第一个Vue 3项目
  5. 如何用手机访问电脑本地的localhost
  6. 最好JavaScript游戏引擎和游戏下载
  7. 如何在Linux下部署Git+Bugzilla+Gogs服务
  8. 开发微信公众号学习之路
  9. react 全家桶安装
  10. 仿小米运动的蓝牙开源项目(附详细实现说明+源码)