五、協同過濾
種類
基於記憶:
基於物品
基於用戶
集成:
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')