机器学习项目(五) 电影推荐系统(四)
五、协同过滤种类基于记忆:基于物品基于用户集成:Combine the Model-based&Memory-based基于模型:矩阵分解深度学习基于用户基于模型不同算法特征值和特征向量AX=λXAX = \lambda XAX=λXX就是特征向量$\lambda $就是特征值A=wλw−1A = w \lambda w^{-1}A=wλw−1SV...
五、协同过滤
种类
基于记忆:
基于物品
基于用户
集成:
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λw−1
SVD的定义
SVD也是对矩阵进行分解,但是和特征分解不同,SVD并不要求分解的矩阵为方阵。假设我们的矩阵A是一个mn的矩阵,那么我们定义矩阵A的SVD为
A
=
U
σ
V
T
A = U \sigma V^T
A=UσVT
其中U是一个mn的矩阵,
σ
\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ΣVT⇒AV=UΣVTV⇒AV=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ΣVT⇒AT=VΣTUT⇒ATA=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}
Am∗n=Um∗nΣm∗nVm∗nT≅Um∗kΣk∗kVk∗nT
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}
Xd∗n′=Ud∗mTXm∗n
可以得到一个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∗μk∗sigmak,遍历未评分的商品列表
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')
更多推荐
所有评论(0)