python写电影推荐系统_Netflix电影推荐系统Python实现(协同过滤+矩阵分解)
1.簡介
要說當(dāng)今社會最火的行業(yè),當(dāng)屬互聯(lián)網(wǎng)行業(yè)。互聯(lián)網(wǎng)行業(yè)的營收主要由廣告收入和用戶付費組成。這兩項都離不開推薦系統(tǒng),廣告需要給不同用戶推薦感興趣的內(nèi)容,實現(xiàn)精準(zhǔn)營銷,而用戶付費如視頻網(wǎng)站等則需要推薦用戶喜歡的內(nèi)容,增加客戶粘性。
作為大數(shù)據(jù)的典型應(yīng)用,今天我們來談?wù)勍扑]系統(tǒng),首先我們簡述一下推薦系統(tǒng)的典型算法,并使用業(yè)界聞名的Netflix競賽數(shù)據(jù)集來實現(xiàn)算法。
問題定義:給定用戶行為矩陣X,X為m*n的矩陣,其中m為用戶數(shù),n 為內(nèi)容數(shù)。已知X中的一部分值,如何猜測未知值?
2.常用算法
常用算法主要有以下三種
(1)基于內(nèi)容的算法
給用戶推薦與之前該用戶評分高的項目相似的項目
構(gòu)建項目向量:選擇一系列的屬性,比如電影可分類為恐怖片、愛情片等,并在這些屬性上為項目評分,如恐怖屬性5分代表驚悚屬性最高,從而得知用戶喜歡那種類型的項目
優(yōu)點:不需考慮其他用戶、可以推薦符合用戶獨特品味的項目、易于解釋
缺點:很難找到合適的特征、冷啟動問題、只能推薦用戶喜歡的項目
(2)協(xié)同過濾算法
為新用戶做推薦時,找到相似的用戶喜歡的內(nèi)容,稱為用戶-用戶協(xié)同過濾
確定新內(nèi)容推薦給哪些用戶時,找到相似的內(nèi)容喜歡的用戶,稱為內(nèi)容-內(nèi)容協(xié)同過濾
相似度度量:
(1)Jaccard similarity: 忽視用戶評分,只考慮是否看過
(2)Cosine similarity: 使用cos函數(shù)度量兩個用戶的距離,未評分的項目有誤差
(3)Pearson correlation: 去均值后度量cosine距離
優(yōu)點:無需選擇特征
缺點:冷啟動問題、用戶矩陣是稀疏的、一些小眾項目無法被推薦
(3)矩陣分解算法
原始的用戶-項目m*k矩陣可以分解為兩個新矩陣,維度分別為m*k和n*k,原始的矩陣是個稀疏矩陣,通過原有數(shù)據(jù)進(jìn)行學(xué)習(xí),使用梯度下降法,最終可求出分解后的矩陣,而原始矩陣中的缺失項可以通過訓(xùn)練出的兩個矩陣乘積計算
3.代碼實現(xiàn)
數(shù)據(jù)集采用Netflix推薦競賽的一個子集,包含10000個用戶和10000個電影,具體的文件格式如下
(1) 用戶列表 users.txt
文件有 10000 行,每行一個整數(shù),表示用戶的 id,文件對應(yīng)本次 Project 的所有用戶。
(2) 訓(xùn)練集 netflix_train.txt
文件包含 689 萬條用戶打分,每行為一次打分,對應(yīng)的格式為: 用戶 id 電影 id 分?jǐn)?shù) 打分日期 其中用戶 id 均出現(xiàn)在 users.txt 中,電影 id 為 1 到 10000 的整數(shù)。各項之間用空格分開
(3) 測試集 netflix_test.txt
文件包含約 172 萬條用戶打分,格式與訓(xùn)練集相同。
3.1 數(shù)據(jù)預(yù)處理
將輸入文件整理成維度為用戶*電影的矩陣 ,其中 對應(yīng)用戶 對電影 的打分
# 導(dǎo)入包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 導(dǎo)入數(shù)據(jù)
user = pd.read_csv("users.txt", names = ['userid'])
netflix_train = pd.read_csv("netflix_train.txt", sep = ' ', names = ['user_id', 'film_id', 'rating', 'date'])
netflix_test = pd.read_csv("netflix_test.txt", sep = ' ', names = ['user_id', 'film_id', 'rating', 'date'])
# 給用戶從零開始進(jìn)行編號
user['id'] = range(len(user))
netflix_train = netflix_train.merge(user, left_on='user_id', right_on='userid')
netflix_test = netflix_test.merge(user, left_on='user_id', right_on='userid')
# 通過數(shù)據(jù)透視函數(shù)構(gòu)建用戶*電影矩陣
X_train = netflix_train.pivot(index='id', columns='film_id', values='rating')
X_test = netflix_test.pivot(index='id', columns='film_id', values='rating')
# 測試集缺失部分電影,補(bǔ)齊為10000*10000矩陣
for i in range(1, 10001):
if i not in X_test.columns:
X_test[i] = np.nan
X_test = X_test.sort_index(axis=1)
# 查看輸出的用戶*電影矩陣
print(X_train.head())
print(X_test.head())
3.2 基于用戶-用戶協(xié)同過濾算法的實現(xiàn)
cosine相似度公式:
評分計算:
注意,此處對于未知值的計算,選擇與該用戶最相近的k個對此項目已評分的用戶進(jìn)行加權(quán)平均
(1)首先用argsort()函數(shù)求出與用戶i最相似的用戶,按照相似度倒序排列成列表indexs
(2)其次按照列表indexs進(jìn)行遍歷,找出看過此電影的相似度排名前三的用戶并計算對電影評分的加權(quán)平均值作為該用戶的評分
考慮到一些局部效應(yīng)的存在,這里對原始算法進(jìn)行了一些改進(jìn),如下圖所示
# Collaborate Filtering
# Compute the overall mean and mean by row and column
mu = np.mean(np.mean(X_train))
bx = np.array(np.mean(X_train, axis=1) - mu)
by = np.array(np.mean(X_train, axis=0) - mu)
# Compute the similarity matrix
X = X_train.sub(bx+mu, axis=0) # Demean
X = X.div(np.sqrt(np.sum(np.square(X), axis=1)), axis=0)
X.fillna(0, inplace=True)
similarity_matrix = np.dot(X, X.T)
# Compute the point matrix using CF
X_train = np.array(X_train.fillna(0))
for i in range(X_train.shape[0]):
indexs = np.argsort(similarity_matrix[i, :])[::-1]
for j in range(X_train.shape[1]):
if X_train[i, j] == 0:
sum = 0
num = 0
simi = 0
k = 0
while num < 3 & k < X_train.shape[1]: # top 3
if X_train[indexs[k], j] > 0:
sum = sum + similarity_matrix[i, indexs[k]] * (X_train[indexs[k], j] - mu - bx[indexs[k]] - by[j])
simi = simi + similarity_matrix[i, indexs[k]]
k = k+1
num = num + 1
else:
k = k+1
if simi != 0:
X_train[i, j] = mu + bx[i] + by[j] + sum/simi
else:
X_train[i, j] = mu + bx[i] + by[j]
else:
continue
# Compute RMSE for the algorithm
RMSE = np.sqrt(np.sum(np.sum(np.square(X_train - X_test)))/netflix_test.shape[0])
print(RMSE)
最終計算得到的RMSE為1.013,基線誤差(預(yù)測得分全部取3的情況)為
,RMSE降低了28.3%
3.3 基于矩陣分解的算法
矩陣分解:
目標(biāo)函數(shù):
通過梯度下降算法迭代更新目標(biāo)函數(shù),獲取最優(yōu)分解矩陣U和V
# Matrix Decomposition
A = X_train > 0
X_train = np.array(X_train.fillna(0))
U = np.random.randn(10000, 100)*0.1
V = np.random.randn(10000, 100)*0.1
alpha = 0.0001
lamda = 1
# Gradient Descent
J = np.zeros((1000))
RMSE = np.zeros((1000))
for i in range(200):
dU = np.dot(np.multiply(A, (np.dot(U, V.T) - X_train)), V) + 2 * lamda * U
dV = np.dot(np.multiply(A, (np.dot(U, V.T) - X_train)), U) + 2 * lamda * V
old_U = U
old_V = V
U = U - alpha/(1+0.1*i) * dU # Learning rate decay
V = V - alpha/(1+0.1*i) * dV
J[i, 0] = 1/2*np.sum(np.sum(np.square(np.multiply(A, (X_train - np.dot(U, V.T)))))) + lamda * np.sum(np.sum(np.square(U)))\
+ lamda * np.sum(np.sum(np.square(V)))
RMSE[i, 0] = np.sqrt(np.sum(np.sum(np.square(np.dot(U, V.T) - X_test)))/netflix_test.shape[0])
print(i)
# Visualization
X = np.dot(U, V.T)
plt.plot(range(1000), RMSE[:, 0])
plt.show()
plt.plot(range(1000), J[:, 0])
plt.show()
print(RMSE[999])
如下圖所示為按照上述參數(shù)迭代1000次后的結(jié)果,隨著迭代次數(shù)的增多,RMSE顯著下降,最后RMSE為1.123,相比于基線誤差降低了20.6%
矩陣分解的算法收斂效果與模型中的正則項系數(shù)
與矩陣維度k是有關(guān),可以嘗試不同的參數(shù)組合,通過RMSE與目標(biāo)函數(shù)值來確定最優(yōu)參數(shù)組合,目標(biāo)函數(shù)值隨著迭代次數(shù)的變化如下圖所示,嘗試的參數(shù)組合分別為
=1, 0.1 以及 矩陣維數(shù)k=100, 50, 10 共2*3=6種,每種參數(shù)組合迭代200次,迭代結(jié)果如下圖所示,可以選擇收斂最快的參數(shù)組合進(jìn)行訓(xùn)練
4.總結(jié)
從上文我們可以看出推薦系統(tǒng)的核心問題是確定用戶-內(nèi)容矩陣(Utility Matrix)
(1)收集已知矩陣信息
通過讓用戶打分或者收集用戶的行為數(shù)據(jù)
(2)從已知矩陣推測未知矩陣信息
通過基于內(nèi)容的方法、協(xié)同過濾方法或者矩陣分解方法推測未知矩陣信息
(3)評價推測方法
常用的標(biāo)準(zhǔn)是RMSE均方根誤差
本文的所有代碼以及數(shù)據(jù)集見下面Github鏈接,大家可以自行下載取用
總結(jié)
以上是生活随笔為你收集整理的python写电影推荐系统_Netflix电影推荐系统Python实现(协同过滤+矩阵分解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不要和诱惑较劲,而应离得越远越好。!!!
- 下一篇: python电影推荐系统 github_