當(dāng)今這個信息爆炸的社會腥椒,每個人都會面對無數(shù)的商品沿猜,無數(shù)的選擇。而推薦算法的目的幫助大家解決選擇困難癥的問題溪烤,在大千世界中推薦專屬于你的商品味咳。
推薦系統(tǒng)算法簡介
這里簡單介紹下推薦系統(tǒng)中最為主要的協(xié)同過濾算法,大致分為如下幾類:
- 基于用戶的協(xié)同過濾(給用戶推薦與他相似的人購買的物品)
- 基于商品的協(xié)同過濾(給用戶推薦和他之前喜歡的物品相似的物品)
- 基于模型的協(xié)同過濾:關(guān)聯(lián)算法檬嘀,聚類算法槽驶,分類算法,回歸算法鸳兽,矩陣分解掂铐,神經(jīng)網(wǎng)絡(luò),圖模型以及隱語義模型都屬于這個范疇。
而本次實戰(zhàn)使用的是矩陣分解算法揍异。
矩陣分解其實是數(shù)學(xué)上的一個經(jīng)典問題全陨。大家從線性代數(shù)中可以知道,矩陣可以做SVD分解衷掷、Cholesky分解等辱姨,就好比任何大于1的正整數(shù)都可以分解成若干質(zhì)數(shù)的乘積,矩陣分解可以認(rèn)為是一種信息壓縮戚嗅。下圖是一個用戶電影評分矩陣雨涛。矩陣的每行表示一個用戶,每列表示一部電影懦胞,矩陣中每個位置的值替久,代表某個用戶對某個電影的評分值。
- R矩陣:用戶對電影的評分組合矩陣躏尉,
- 用戶矩陣蚯根,每一個被壓縮的行向量代表一個用戶的信息向量,
- 電影矩陣胀糜,每一個被壓縮列向量代表一個電影的信息向量颅拦。
而這樣的矩陣分解壓縮過程,使得用戶矩陣和電影矩陣都具有了一定的語義信息教藻,必須強(qiáng)調(diào)的是用戶矩陣行向量的維數(shù)和電影矩陣列向量維數(shù)是相等的距帅。所以本質(zhì)上就是將每個用戶和每個電影通過已有的打分信息Embedding到同一維度的信息向量空間。
接下來我們就學(xué)習(xí)一下如何使用keras對R矩陣進(jìn)行矩陣分解怖竭,獲得每個電影和每個用戶的信息向量锥债。
推薦系統(tǒng)實戰(zhàn)
數(shù)據(jù)載入
import pandas as pd
import numpy as np
rating = pd.read_csv("./ml-latest-small/ratings.csv",sep=",")
num_user = np.max(rating["userId"])
num_movie = np.max(rating["movieId"])
print(num_user,num_movie,len(rating))
數(shù)據(jù)格式如下,第一列是index痊臭,第二列是用戶ID哮肚,第三列是電影ID,第四列示評分。
userId movieId rating
0 1 1 4.0
1 1 3 4.0
2 1 6 4.0
3 1 47 5.0
......
100831 610 166534 4.0
100832 610 168248 5.0
100833 610 168250 5.0
100834 610 168252 5.0
100835 610 170875 3.0
其中num_user = 610, num_movie = 193609 len(rating)=100836广匙。意味著我的數(shù)據(jù)中有610為觀眾允趟,193609 部電影,得到了100836個評分?jǐn)?shù)據(jù)鸦致。從這些我們可以計算出上圖用戶電影組合的R矩陣的填充率潮剪。
這說明只有0.8%的用戶電影組合有評分涣楷,當(dāng)然這和實際情況是相符的,畢竟一個人只會給很少部分的電影評分抗碰,所以我們發(fā)現(xiàn)用戶對電影的評分組合矩陣R極其稀疏狮斗。所以接下來我們要做的就是預(yù)測那些沒有評分的用戶電影組合可能的得分,填充R矩陣弧蝇,這樣就可以為用戶推薦模型預(yù)測得分較高的電影碳褒。
模型搭建
from keras import Model
import keras.backend as K
from keras.layers import Embedding,Reshape,Input,Dot
K.clear_session()
def Recmand_model(num_user,num_movie,k):
input_uer = Input(shape=[None,],dtype="int32")
model_uer = Embedding(num_user+1,k,input_length = 1)(input_uer)
model_uer = Reshape((k,))(model_uer)
input_movie = Input(shape=[None,],dtype="int32")
model_movie = Embedding(num_movie+1,k,input_length = 1)(input_movie)
model_movie = Reshape((k,))(model_movie)
out = Dot(1)([model_uer,model_movie])
model = Model(inputs=[input_uer,input_movie], outputs=out)
model.compile(loss='mse', optimizer='Adam')
model.summary()
return model
這里就是矩陣分解的部分,模型的架構(gòu)圖如下圖所示:將用戶和電影通過Eembdding層壓縮到k維度向量看疗,然后簡單粗暴直接向量點乘沙峻,得到用戶對電影的預(yù)測評分。這里誤差采用平方誤差MSE两芳,優(yōu)化器采用的是Adam摔寨。
model = Recmand_model(num_user,num_movie,100)
運行上方代碼就可以構(gòu)建好模型,這里筆者將用戶和電影都embedding的100維的向量空間中怖辆。
數(shù)據(jù)準(zhǔn)備
將數(shù)據(jù)準(zhǔn)備成( [用戶ID, 電影ID] , 用戶ID對電影ID的評分 )這種格式是复。接下來就可以把數(shù)據(jù)喂給模型了。
train_user = rating["userId"].values
train_movie = rating["movieId"].values
train_x = [train_user,train_movie]
train_y = rating["rating"].values
拿到輸入數(shù)據(jù)之后疗隶,設(shè)置好batch_size,epoch佑笋,就可以進(jìn)行訓(xùn)練了翼闹。運行下面代碼讓模型跑起來斑鼻。
模型訓(xùn)練
model.fit(train_x,train_y,batch_size = 100,epochs =10)
十個epoch之后loss只有0.09,這樣我們就可以不嚴(yán)謹(jǐn)?shù)南陆Y(jié)論:模型的預(yù)測誤差不超出0.1猎荠,接下來是預(yù)測部分坚弱。
模型預(yù)測
從之前讀入數(shù)據(jù)中可以得知,userId為1的用戶关摇,沒有對movieId為2的電影評分荒叶。我們就用模型試試userId為1的用戶會為movieId為2的電影打多少數(shù)分呢?運行下方代碼输虱,便能知曉些楣。
model.predict([[1],[2]])
輸出結(jié)果:array([[3.9732044]], dtype=float32)
模型預(yù)測為3.9,而評分的總分為5分宪睹,意味著userId為1的用戶很有可能會喜歡movieId為2的電影愁茁。可以考慮將movieId為2的電影推薦給userId為1的用戶亭病。
結(jié)語
這里只是采用了最簡單的方式做了一個簡單的推薦系統(tǒng)鹅很,而且此方式很難解決新的電影和新的用戶的推薦問題。推薦系統(tǒng)是門很深的學(xué)問罪帖,算法不僅需要考慮到推薦的準(zhǔn)確率促煮,覆蓋率邮屁,還要考慮到推薦內(nèi)容的豐富性和新穎性。人是很容易改變和厭倦的動物菠齿,所以佑吝,筆者有時候在想真會出現(xiàn)一個一直都懂你的推薦算法嗎?