五、协同过滤

种类

基于记忆:
基于物品
基于用户

集成:

Combine the Model-based&Memory-based

基于模型:

矩阵分解
深度学习

在这里插入图片描述

基于用户
在这里插入图片描述

基于模型
不同算法
在这里插入图片描述

特征值和特征向量
A X = λ X AX = \lambda X AX=λX
X就是特征向量
$\lambda $就是特征值

A = w λ w − 1 A = w \lambda w^{-1} A=wλw1

SVD的定义

SVD也是对矩阵进行分解,但是和特征分解不同,SVD并不要求分解的矩阵为方阵。假设我们的矩阵A是一个mn的矩阵,那么我们定义矩阵A的SVD为
A = U σ V T A = U \sigma V^T A=UσVT
其中U是一个m
n的矩阵, σ \sigma σ是一个mn矩阵,除了主对角线上的元素以外全为0,主对角线上的每个元素都称为奇异值,V是一个nm的矩阵,U和V都是酉矩阵(实正交矩阵),即满足 V T V = I , U T U = I V^T V = I,U^T U = I VTV=I,UTU=I

右奇异向量求解

如果我们将A的装置和A做矩阵乘法,那么会得到n*n的一个方阵 A T A A^TA ATA,既然 A T A A^TA ATA是方阵,那么我们就可以进行特征分解,得到的特征值和特征向量满足下式:
( A T A ) v i = λ v i (A^TA)v_i = \lambda v_i (ATA)vi=λvi
得到:矩阵 A T A A^TA ATA的n个特征值和对应的n个特征向量v。
A = U Σ V T ⇒ A V = U Σ V T V ⇒ A V = U Σ ⇒ A v i = σ i μ i ⇒ σ i = A v i / μ i \mathbf{A}=\mathbf{U} \Sigma V^{T} \Rightarrow \mathbf{A} \mathbf{V}=\mathbf{U} \Sigma V^{T} \mathbf{V} \Rightarrow \mathbf{A} \mathbf{V}=\mathbf{U} \mathbf{\Sigma} \Rightarrow \mathbf{A} \boldsymbol{v}_{i}=\boldsymbol{\sigma}_{i} \boldsymbol{\mu}_{i} \Rightarrow \boldsymbol{\sigma}_{i}=\mathbf{A} \boldsymbol{v}_{i} / \boldsymbol{\mu}_{i} A=UΣVTAV=UΣVTVAV=UΣAvi=σiμiσi=Avi/μi
这样我们可以求出我们的每个奇异值,进而求出奇异值矩阵 Σ \Sigma Σ
A = U Σ V T ⇒ A T = V Σ T U T ⇒ A T A = V Σ T U T U Σ V T = V Σ 2 V T \mathrm{A}=\mathrm{U} \Sigma \mathrm{V}^{\mathrm{T}} \Rightarrow \mathrm{A}^{\mathrm{T}}=\mathrm{V} \Sigma^{\mathrm{T}} \mathrm{U}^{\mathrm{T}} \Rightarrow \mathrm{A}^{\mathrm{T}} \mathrm{A}=\mathrm{V} \Sigma^{\mathrm{T}} \mathrm{U}^{\mathrm{T}} \mathrm{U} \Sigma \mathrm{V}^{\mathrm{T}}=\mathrm{V} \Sigma^{2} \mathrm{V}^{\mathrm{T}} A=UΣVTAT=VΣTUTATA=VΣTUTUΣVT=VΣ2VT

SVD的一些性质

大矩阵分解
A m ∗ n = U m ∗ n Σ m ∗ n V m ∗ n T ≅ U m ∗ k Σ k ∗ k V k ∗ n T A_{m * n}=U_{m * n} \Sigma_{m * n} V_{m * n}^{T} \cong U_{m * k} \Sigma_{k * k} V_{k * n}^{T} Amn=UmnΣmnVmnTUmkΣkkVknT

SVD用于PCA降维
假设样本时mn的矩阵X,如果我们通过SVD找到了矩阵 X T X X^TX XTX最大的d个特征向量张成的md维矩阵U,则做如下处理
X d ∗ n ′ = U d ∗ m T X m ∗ n X_{\mathrm{d} * n}^{\prime}=U_{\mathrm{d} * m}^{T} X_{\mathrm{m} * n} Xdn=UdmTXmn
可以得到一个dn的矩阵 x ′ x^{\prime} x,这个矩阵和我们原来的mn维样本矩阵X相比,行数从m减到了d,可见对行数进行了压缩
做奇异矩阵可以用于行数的压缩,相对的,右奇异矩阵可以用于列数即特征维度的压缩,也就是我们的PCA降维

数据压缩
ρ = n 2 k ( 2 n + 1 ) \rho=\frac{n^{2}}{k(2 n+1)} ρ=k(2n+1)n2

推荐系统

当给定一个打分矩阵时,矩阵中行代表用户user,列代表物品item,其中的值代表用户对物品的打分
基于svd的优势在于:用户的评分数据是稀疏矩阵,可以用SVD将原始数据映射到低维空间中,然后计算物品item之间的相似度,可以节省计算资源
整体思路:找到用户没有评分的物品,然后再经过SVD"压缩"后的低维空间中,计算未评分物品与其他物品的相似性,得到一个预测打分,再对这些物品的评分从高到低进行排序,返回前N个物品推荐给用户

推荐系统实现

一、用户未评分的商品列表,对打分矩阵A做SVD,得到三个矩阵 U , Σ , V T U,\Sigma,V^T U,Σ,VT
二、选定留下k个特征值、特征向量,取u矩阵的前k列,得到 μ k \mu_k μk,取sigma的前k个值,得到 s i g m a k sigma_k sigmak
三、 R = A T ∗ μ k ∗ s i g m a k R = A^T * \mu_k *sigma_k R=ATμksigmak,遍历未评分的商品列表

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')

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐