1.SVD在推荐系统中的应用简介
此部分可以详见:SVD奇异值分解的基本原理介绍
2.SVD的TopK推荐系统的简介
TopK推荐策略就是指:找到和新用户最高相似度的TopK旧用户,将这k个旧用户评分而新用户未评分的所有商品推荐给新用户
每个旧用户对商品的评分都有一个权值,权值大小正相关于和新用户的相似度
注:本文系统还实现了推荐的商品是按照综合评分降序的顺序给出的~,用pandas.DataFrame很容易达到
3.svd TopK推荐系统的Python实现(Release版本)
3.1代码
# -*- coding: utf-8 -*-
"""
@author: 蔚蓝的天空Tom
Talk is cheap, show me the code
Aim:基于svd的推荐系统(推荐策略:topK)的代码实现(Release版本)
"""
import numpy as np
import pandas as pd
from pandas import DataFrame
class CSVD(object):
'''
实现基于svd的推荐系统
推荐策略:找到和新用户相似度最高的旧用户,找到旧用户评分商品但新用户没有评分的商品,将这些商品推荐给新用户
此系统是按照评分降序的顺序将商品推荐给用户
'''
def __init__(self, data):
self.data = data #用户数据
self.S = [] #用户数据矩阵的奇异值序列 singular values
self.U = [] #svd后的单位正交向量
self.VT = [] #svd后的单位正交向量
self.k = 0 #满足self.p的最小k值(k表示奇异值的个数)
self.SD = [] #对角矩阵,对角线上元素是奇异值 singular values diagonal matrix
self.n = np.shape(data)[0] #用户对商品的评分矩阵中,商品个数
self.m = np.shape(data)[1] #用户对商品的评分矩阵中,用户个数
def _svd(self):
'''
用户数据矩阵的svd奇异值分解
'''
self.U, self.S, self.VT = np.linalg.svd(self.data)
return self.U, self.S, self.VT
def _calc_k(self, percentge):
'''确定k值:前k个奇异值的平方和占比 >=percentage, 求满足此条件的最小k值
:param percentage, 奇异值平方和的占比的阈值
:return 满足阈值percentage的最小k值
'''
self.k = 0
#用户数据矩阵的奇异值序列的平方和
total = sum(np.square(self.S))
svss = 0 #奇异值平方和 singular values square sum
for i in range(np.shape(self.S)[0]):
svss += np.square(self.S[i])
if (svss/total) >= percentge:
self.k = i+1
break
return self.k
def _buildSD(self, k):
'''构建由奇异值组成的对角矩阵
:param k,根据奇异值开放和的占比阈值计算出来的k值
:return 由k个前奇异值组成的对角矩阵
'''
#方法1:用数组乘方法
self.SD = np.eye(self.k) * self.S[:self.k]
#方法2:用自定义方法
e = np.eye(self.k)
for i in range(self.k):
e[i,i] = self.S[i]
return self.SD
def _dimReduce(self, percentage):
'''
SVD降维
:param percentage, 奇异值开方和的占比阈值
:return 降维后的用户数据矩阵
'''
#Step1:svd奇异值分解
self._svd()
#Step2:计算k值
self._calc_k(percentage)
print('\n按照奇异值开方和占比阈值percentage=%d, 求得降维的k=%d'%(percentage, self.k))
#Step3:构建由奇异值组成的对角矩阵singular values diagonal
self._buildSD(self.k)
k,U,SD,VT = self.k,self.U, self.SD, self.VT
#Step4:按照svd分解公式对用户数据矩阵进行降维,得到降维压缩后的数据矩阵
a = U[:len(U), :k]
b = np.dot(SD, VT[:k, :len(VT)])
newData = np.dot(a,b)
return newData