五、协同过滤
种类
基于记忆:
基于物品
基于用户
集成:
Combine the Model-based&Memory-based
基于模型:
矩阵分解
深度学习
基于用户
基于模型
不同算法
特征值和特征向量
X就是特征向量
$\lambda $就是特征值
SVD的定义
SVD也是对矩阵进行分解,但是和特征分解不同,SVD并不要求分解的矩阵为方阵。假设我们的矩阵A是一个mn的矩阵,那么我们定义矩阵A的SVD为
其中U是一个mn的矩阵,是一个mn矩阵,除了主对角线上的元素以外全为0,主对角线上的每个元素都称为奇异值,V是一个nm的矩阵,U和V都是酉矩阵(实正交矩阵),即满足
右奇异向量求解
如果我们将A的装置和A做矩阵乘法,那么会得到n*n的一个方阵,既然是方阵,那么我们就可以进行特征分解,得到的特征值和特征向量满足下式:
得到:矩阵的n个特征值和对应的n个特征向量v。
这样我们可以求出我们的每个奇异值,进而求出奇异值矩阵
SVD的一些性质
大矩阵分解
SVD用于PCA降维
假设样本时mn的矩阵X,如果我们通过SVD找到了矩阵最大的d个特征向量张成的md维矩阵U,则做如下处理
可以得到一个dn的矩阵,这个矩阵和我们原来的mn维样本矩阵X相比,行数从m减到了d,可见对行数进行了压缩
做奇异矩阵可以用于行数的压缩,相对的,右奇异矩阵可以用于列数即特征维度的压缩,也就是我们的PCA降维
数据压缩
推荐系统
当给定一个打分矩阵时,矩阵中行代表用户user,列代表物品item,其中的值代表用户对物品的打分
基于svd的优势在于:用户的评分数据是稀疏矩阵,可以用SVD将原始数据映射到低维空间中,然后计算物品item之间的相似度,可以节省计算资源
整体思路:找到用户没有评分的物品,然后再经过SVD"压缩"后的低维空间中,计算未评分物品与其他物品的相似性,得到一个预测打分,再对这些物品的评分从高到低进行排序,返回前N个物品推荐给用户
推荐系统实现
一、用户未评分的商品列表,对打分矩阵A做SVD,得到三个矩阵
二、选定留下k个特征值、特征向量,取u矩阵的前k列,得到,取sigma的前k个值,得到
三、,遍历未评分的商品列表
import pandas as pd
from surprise import Reader, Dataset, SVD, evaluate
import numpy as np
reader = Reader()
ratings = pd.read_csv('../input/ratings_small.csv')
ratings.head()
data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader)
data.split(n_folds=5)
svd = SVD()
evaluate(svd, data, measures=['RMSE', 'MAE'])
trainset = data.build_full_trainset()
svd.train(trainset)
ratings[ratings['userId'] == 1]
svd.predict(1, 302, 3)
def convert_int(x):
try:
return int(x)
except:
return np.nan
id_map = pd.read_csv('../input/links_small.csv')[['movieId', 'tmdbId']]
id_map['tmdbId'] = id_map['tmdbId'].apply(convert_int)
id_map.columns = ['movieId', 'id']
id_map = id_map.merge(smd[['title', 'id']], on='id').set_index('title')
#id_map = id_map.set_index('tmdbId')
indices_map = id_map.set_index('id')
def hybrid(userId, title):
idx = indices[title]
tmdbId = id_map.loc[title]['id']
# print(idx)
movie_id = id_map.loc[title]['movieId']
sim_scores = list(enumerate(cosine_sim[int(idx)]))
sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
sim_scores = sim_scores[1:26]
movie_indices = [i[0] for i in sim_scores]
movies = smd.iloc[movie_indices][['title', 'vote_count', 'vote_average', 'year', 'id']]
movies['est'] = movies['id'].apply(lambda x: svd.predict(userId, indices_map.loc[x]['movieId']).est)
movies = movies.sort_values('est', ascending=False)
return movies.head(10)
hybrid(1, 'Avatar')
hybrid(500, 'Avatar')