python写电影推荐系统_Netflix电影推荐系统Python实现(协同过滤+矩阵分解)
1.簡(jiǎn)介
要說(shuō)當(dāng)今社會(huì)最火的行業(yè),當(dāng)屬互聯(lián)網(wǎng)行業(yè)。互聯(lián)網(wǎng)行業(yè)的營(yíng)收主要由廣告收入和用戶付費(fèi)組成。這兩項(xiàng)都離不開推薦系統(tǒng),廣告需要給不同用戶推薦感興趣的內(nèi)容,實(shí)現(xiàn)精準(zhǔn)營(yíng)銷,而用戶付費(fèi)如視頻網(wǎng)站等則需要推薦用戶喜歡的內(nèi)容,增加客戶粘性。
作為大數(shù)據(jù)的典型應(yīng)用,今天我們來(lái)談?wù)勍扑]系統(tǒng),首先我們簡(jiǎn)述一下推薦系統(tǒng)的典型算法,并使用業(yè)界聞名的Netflix競(jìng)賽數(shù)據(jù)集來(lái)實(shí)現(xiàn)算法。
問(wèn)題定義:給定用戶行為矩陣X,X為m*n的矩陣,其中m為用戶數(shù),n 為內(nèi)容數(shù)。已知X中的一部分值,如何猜測(cè)未知值?
2.常用算法
常用算法主要有以下三種
(1)基于內(nèi)容的算法
給用戶推薦與之前該用戶評(píng)分高的項(xiàng)目相似的項(xiàng)目
構(gòu)建項(xiàng)目向量:選擇一系列的屬性,比如電影可分類為恐怖片、愛情片等,并在這些屬性上為項(xiàng)目評(píng)分,如恐怖屬性5分代表驚悚屬性最高,從而得知用戶喜歡那種類型的項(xiàng)目
優(yōu)點(diǎn):不需考慮其他用戶、可以推薦符合用戶獨(dú)特品味的項(xiàng)目、易于解釋
缺點(diǎn):很難找到合適的特征、冷啟動(dòng)問(wèn)題、只能推薦用戶喜歡的項(xiàng)目
(2)協(xié)同過(guò)濾算法
為新用戶做推薦時(shí),找到相似的用戶喜歡的內(nèi)容,稱為用戶-用戶協(xié)同過(guò)濾
確定新內(nèi)容推薦給哪些用戶時(shí),找到相似的內(nèi)容喜歡的用戶,稱為內(nèi)容-內(nèi)容協(xié)同過(guò)濾
相似度度量:
(1)Jaccard similarity: 忽視用戶評(píng)分,只考慮是否看過(guò)
(2)Cosine similarity: 使用cos函數(shù)度量?jī)蓚€(gè)用戶的距離,未評(píng)分的項(xiàng)目有誤差
(3)Pearson correlation: 去均值后度量cosine距離
優(yōu)點(diǎn):無(wú)需選擇特征
缺點(diǎn):冷啟動(dòng)問(wèn)題、用戶矩陣是稀疏的、一些小眾項(xiàng)目無(wú)法被推薦
(3)矩陣分解算法
原始的用戶-項(xiàng)目m*k矩陣可以分解為兩個(gè)新矩陣,維度分別為m*k和n*k,原始的矩陣是個(gè)稀疏矩陣,通過(guò)原有數(shù)據(jù)進(jìn)行學(xué)習(xí),使用梯度下降法,最終可求出分解后的矩陣,而原始矩陣中的缺失項(xiàng)可以通過(guò)訓(xùn)練出的兩個(gè)矩陣乘積計(jì)算
3.代碼實(shí)現(xiàn)
數(shù)據(jù)集采用Netflix推薦競(jìng)賽的一個(gè)子集,包含10000個(gè)用戶和10000個(gè)電影,具體的文件格式如下
(1) 用戶列表 users.txt
文件有 10000 行,每行一個(gè)整數(shù),表示用戶的 id,文件對(duì)應(yīng)本次 Project 的所有用戶。
(2) 訓(xùn)練集 netflix_train.txt
文件包含 689 萬(wàn)條用戶打分,每行為一次打分,對(duì)應(yīng)的格式為: 用戶 id 電影 id 分?jǐn)?shù) 打分日期 其中用戶 id 均出現(xiàn)在 users.txt 中,電影 id 為 1 到 10000 的整數(shù)。各項(xiàng)之間用空格分開
(3) 測(cè)試集 netflix_test.txt
文件包含約 172 萬(wàn)條用戶打分,格式與訓(xùn)練集相同。
3.1 數(shù)據(jù)預(yù)處理
將輸入文件整理成維度為用戶*電影的矩陣 ,其中 對(duì)應(yīng)用戶 對(duì)電影 的打分
# 導(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)行編號(hào)
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')
# 通過(guò)數(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')
# 測(cè)試集缺失部分電影,補(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é)同過(guò)濾算法的實(shí)現(xiàn)
cosine相似度公式:
評(píng)分計(jì)算:
注意,此處對(duì)于未知值的計(jì)算,選擇與該用戶最相近的k個(gè)對(duì)此項(xiàng)目已評(píng)分的用戶進(jìn)行加權(quán)平均
(1)首先用argsort()函數(shù)求出與用戶i最相似的用戶,按照相似度倒序排列成列表indexs
(2)其次按照列表indexs進(jìn)行遍歷,找出看過(guò)此電影的相似度排名前三的用戶并計(jì)算對(duì)電影評(píng)分的加權(quán)平均值作為該用戶的評(píng)分
考慮到一些局部效應(yīng)的存在,這里對(duì)原始算法進(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)
最終計(jì)算得到的RMSE為1.013,基線誤差(預(yù)測(cè)得分全部取3的情況)為
,RMSE降低了28.3%
3.3 基于矩陣分解的算法
矩陣分解:
目標(biāo)函數(shù):
通過(guò)梯度下降算法迭代更新目標(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%
矩陣分解的算法收斂效果與模型中的正則項(xiàng)系數(shù)
與矩陣維度k是有關(guān),可以嘗試不同的參數(shù)組合,通過(guò)RMSE與目標(biāo)函數(shù)值來(lái)確定最優(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)的核心問(wèn)題是確定用戶-內(nèi)容矩陣(Utility Matrix)
(1)收集已知矩陣信息
通過(guò)讓用戶打分或者收集用戶的行為數(shù)據(jù)
(2)從已知矩陣推測(cè)未知矩陣信息
通過(guò)基于內(nèi)容的方法、協(xié)同過(guò)濾方法或者矩陣分解方法推測(cè)未知矩陣信息
(3)評(píng)價(jià)推測(cè)方法
常用的標(biāo)準(zhǔn)是RMSE均方根誤差
本文的所有代碼以及數(shù)據(jù)集見下面Github鏈接,大家可以自行下載取用
總結(jié)
以上是生活随笔為你收集整理的python写电影推荐系统_Netflix电影推荐系统Python实现(协同过滤+矩阵分解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 不要和诱惑较劲,而应离得越远越好。!!!
- 下一篇: 解决若干WTL与VS2010的兼容问题(