精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

推薦系統-協同過濾在Spark中的實現

移動開發
本文以經典的協同過濾為切入點,重點介紹了被工業界廣泛使用的矩陣分解算法,從理論與實踐兩個維度介紹了該算法的原理,通俗易懂,希望能夠給大家帶來一些啟發。

作者 | vivo 互聯網服務器團隊-Tang Shutao

現如今推薦無處不在,例如抖音、淘寶、京東App均能見到推薦系統的身影,其背后涉及許多的技術。

本文以經典的協同過濾為切入點,重點介紹了被工業界廣泛使用的矩陣分解算法,從理論與實踐兩個維度介紹了該算法的原理,通俗易懂,希望能夠給大家帶來一些啟發。

筆者認為要徹底搞懂一篇論文,最好的方式就是動手復現它,復現的過程你會遇到各種各樣的疑惑、理論細節。

一、 背景

1.1 引言

在信息爆炸的二十一世紀,人們很容易淹沒在知識的海洋中,在該場景下搜索引擎可以幫助我們迅速找到我們想要查找的內容。

在電商場景,如今的社會物質極大豐富,商品琳瑯滿目,種類繁多。消費者很容易挑花眼,即用戶將會面臨信息過載的問題。

為了解決該問題,推薦引擎應運而生。例如我們打開淘寶App,JD app,B站視頻app,每一個場景下都有推薦的模塊。

那么此時有一個幼兒園小朋友突然問你,為什么JD給你推薦這本《程序員頸椎康復指南》?你可能會回答,因為我的職業是程序員。

接著小朋友又問,為什么《Spark大數據分析》這本書排在第6個推薦位,而《Scala編程》排在第2位?這時你可能無法回答這個問題。

為了回答該問題,我們設想下面的場景:

在JD的電商系統中,存在著用戶和商品兩種角色,并且我們假設用戶都會對自己購買的商品打一個0-5之間的分數,分數越高代表越喜歡該商品。

基于此假設,我們將上面的問題轉化為用戶對《程序員頸椎康復指南》,《Spark大數據分析》,《Scala編程》這三本書打分的話,用戶會打多少分(用戶之前未購買過這3本書)。因此物品在頁面的先后順序就等價于預測用戶對這些物品的評分,并且根據這些評分進行排序的問題。

為了便于預測用戶對物品的評分問題,我們將所有三元組(User, Item, Rating),即用戶User給自己購買的商品Item的評分為Rating,組織為如下的矩陣形式:

圖片

其中,表格包含 m 個用戶和n個物品,將表格定義為評分矩陣 Rm×nRm×n  ,其中的元素 ru,iru,i 表示第u個用戶對第i個物品的評分。

例如,在上面的表格中,用戶user-1購買了物品 item-1, item-3, item-4,并且分別給出了4,2,5的評分。最終,我們將原問題轉化為預測白色空格處的數值。

1.2 協同過濾

協同過濾,簡單來說是利用與用戶興趣相投、擁有共同經驗之群體的喜好來推薦給用戶感興趣的物品。興趣相投使用數學語言來表達就是相似度  (人與人,物與物)。因此,根據相似度的對象,協同過濾可以分為基于用戶的協同過濾和基于物品的協同過濾。

以評分矩陣為例,以行方向觀測評分矩陣,每一行代表每個用戶的向量表示,例如用戶user-1的向量為 [4, 0, 2, 5, 0, 0]。以列方向觀測評分矩陣,每一列表示每個物品的向量表示,例如物品item-1的向量為[4, 3, 0, 0, 5]。

基于向量表示,相似度的計算有多種公式,例如余弦相似度,歐氏距離,皮爾森。這里我們以余弦相似度為例,它是我們中學學過的向量夾角 (中學只涉及2維和3維) 的高維推廣,余弦相似度公式很容易理解和使用。給定兩個向量 A={a1,?,an}A={a1,?,an} 和?B={b1,?,bn}B={b1,?,bn} ,其夾角定義如下:

圖片

例如,我們計算user-3和user-4的余弦相似度,二者對應的向量分別為 [0, 2, 0, 3, 0, 4],[0, 3, 3, 5, 4, 0]

圖片

向量夾角的余弦值越接近1代表兩個物品方向越接近平行,也就是越相似,反之越接近-1代表兩個物品方向越接近反向,表示兩個物品相似度接近相反,接近0,表示向量接近垂直/正交,兩個物品幾乎無關聯。顯然,這和人的直覺完全一致。

例如,我們在視頻App中經常能看到"相關推薦"模塊,其背后用到的原理之一就是相似度計算,下圖展示了一個具體的例子。

我們用《血族第一部》在向量庫 (存儲向量的數據庫,該系統能夠根據輸入向量,用相似度公式在庫中進行檢索,找出TopN的候選向量) 里面進行相似度檢索,找到了前7部高相似度的影片,值得注意的是第一部是自己本身,相似度為1.0,其他三部是《血族》的其他3部同系列作品。

圖片

1.2.1 基于用戶的協同過濾 (UserCF)

基于用戶的協同過濾分為兩步

  1. 找出用戶相似度TopN的若干用戶。
  2. 根據TopN用戶評分的物品,形成候選物品集合,利用加權平均預估用戶u對每個候選物品的評分。

圖片

例如,由用戶u的相似用戶{u1, u3, u5, u9}可得候選物品為

圖片

我們現在預測用戶u對物品i1的評分,由于物品在兩個用戶{u1, u5}的購買記錄里,因此用戶u對物品i1的預測評分為:

圖片

其中sim(u,u1)sim(u,u1) 表示用戶 u與用戶 u1u1的相似度。

在推薦時,根據用戶u對所有候選物品的預測分進行排序,取TopM的候選物品推薦給用戶u即可。

1.2.2 基于物品的協同過濾 (ItemCF)

圖片

基于物品的協同過濾分為兩步

  1. 在用戶u購買的物品集合中,選取與每一個物品TopN相似的物品。
  2. TopN相似物品形成候選物品集合,利用加權平均預估用戶u對每個候選物品的評分。

例如,我們預測用戶u對物品i3的評分,由于物品i3與物品{i6, i1, i9}均相似,因此用戶u對物品i3的預測評分為:

圖片

其中 sim(i6,i3)sim(i6,i3)  表示物品 i6i6  與物品 i3的相似度,其他符號同理。

圖片

1.2.3 UserCF與ItemCF的比較

我們對ItemCF和UserCF做如下總結:

UserCF主要用于給用戶推薦那些與之有共同興趣愛好的用戶喜歡的物品,其推薦結果著重于反映和用戶興趣相似的小群體的熱點,更社會化一些,反映了用戶所在的小型興趣群體中物品的熱門程度。在實際應用中,UserCF通常被應用于用于新聞推薦。

ItemCF給用戶推薦那些和他之前喜歡的物品類似的物品,即ItemCF的推薦結果著重于維系用戶的歷史興趣,推薦更加個性化,反應用戶自己的興趣。在實際應用中,圖書、電影平臺使用ItemCF,比如豆瓣、亞馬遜、Netflix等。

除了基于用戶和基于物品的協同過濾,還有一類基于模型的協同過濾算法,如上圖所示。此外基于用戶和基于物品的協同過濾又可以歸類為基于鄰域 (K-Nearest Neighbor, KNN) 的算法,本質都是在找"TopN鄰居",然后利用鄰居和相似度進行預測。

二、矩陣分解

經典的協同過濾算法本身存在一些缺點,其中最明顯的就是稀疏性問題。我們知道評分矩陣是一個大型稀疏矩陣,導致在計算相似度時,兩個向量的點積等于0 (以余弦相似度為例)。為了更直觀的理解這一點,我們舉例如下:

rom sklearn.metrics.pairwise import cosine_similarity
a = [
[ 0, 0, 0, 3, 2, 0, 3.5, 0, 1 ],
[ 0, 1, 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 1, 0, 0, 0, 0, 0, 0 ],
[4.1, 3.8, 4.6, 3.8, 4.4, 3, 4, 0, 3.6]
]
cosine_similarity(a)
# array([[1. , 0. , 0. , 0.66209271],
# [0. , 1. , 0. , 0.34101639],
# [0. , 0. , 1. , 0.41280932],
# [0.66209271, 0.34101639, 0.41280932, 1. ]])

圖片

我們從評分矩陣中抽取item1 - item4的向量,并且利用余弦相似度計算它們之間的相似度。

通過相似度矩陣,我們可以看到物品item-1, item-2, item-3的之間的相似度均為0,而且與item-1, item-2, item-3最相似的物品都是item-4,因此在以ItemCF為基礎的推薦場景中item-4將會被推薦給用戶。

但是,物品item-4與物品item-1, item-2, item-3最相似的原因是item-4是一件熱門商品,購買的用戶多,而物品item-1, item-2, item-3的相似度均為0的原因僅僅是它們的特征向量非常稀疏,缺乏相似度計算的直接數據。

綜上,我們可以看到經典的基于用戶/物品的協同過濾算法有天然的缺陷,無法處理稀疏場景。為了解決該問題,矩陣分解被提出。

2.1 顯示反饋

我們將用戶對物品的評分行為定義為顯示反饋?;陲@示反饋的矩陣分解是將評分矩陣Rm×n 用兩個矩陣 Xm×k和Yn×k的乘積近似表示,其數學表示如下:

圖片

其中, k?m/nk?m/n 表示隱性因子,以用戶側來理解,?k=2k=2 表示的就是用戶的年齡和性別兩個屬性。此外有個很好的比喻就是物理學的三棱鏡,白光在三棱鏡的作用下被分解為7種顏色的光,在矩陣分解算法中,分解的作用就類似于"三棱鏡",如下圖所示,因此,矩陣分解也被稱為隱語義模型。矩陣分解將系統的自由度從 O(mn) 降到了O((m+n)k,從而實現了降維的目的。

圖片

為了求解矩陣?Xm×kXm×k 和Yn×k,需要最小化平方誤差損失函數,來盡可能地使得兩個矩陣的乘積逼近評分矩陣 Rm×nRm×n ,即

圖片

其中, λ(∑uxTuxu+∑iyTiyi)λ(∑uxuTxu+∑iyiTyi) 為懲罰項,λ為懲罰系數/正則化系數,xu表示第u個用戶的k維特征向量,yiyi  表示第 i 個物品的k維特征向量。

圖片

全體用戶的特征向量構成了用戶矩陣 ?Xm×kXm×k ,全體物品的特征向量構成了物品矩陣 Yn×k。

圖片

我們訓練模型的時候,就只需要訓練用戶矩陣中的m×k個參數和物品矩陣中的n×k個參數。因此,協同過濾就成功轉化成了一個優化問題。

2.2 預測評分

通過模型訓練 (即求解模型系數的過程),我們得到用戶矩陣Xm×k 和物品矩陣 Yn×kYn×k,全部用戶對全部物品的評分預測可以通過  Xm×k(Yn×k)TXm×k(Yn×k)T 獲得。如下圖所示。

圖片

得到全部的評分預測后,我們就可以對每個物品進行擇優推薦。需要注意的是,用戶矩陣和物品矩陣的乘積,得到的評分預估值,與用戶的實際評分不是全等關系,而是近似相等的關系。如上圖中兩個矩陣粉色部分,用戶實際評分和預估評分都是近似的,有一定的誤差。

2.3 理論推導

矩陣分解ALS的理論推導網上也有不少,但是很多推導不是那么嚴謹,在操作向量導數時有的步驟甚至是錯誤的。有的博主對損失函數的求和項理解解出現錯誤,例如

圖片

但是評分矩陣是稀疏的,求和并不會貫穿整個用戶集和物品集。正確的寫法應該是

圖片

其中,(u,i) is known(u,i) is known表示已知的評分項。

我們在本節給出詳細的、正確的推導過程,一是當做數學小練習,其次也是對算法有更深層的理解,便于閱讀Spark ALS的源碼。

將?(u,i) is known(u,i) is known 使用數學語言描述,矩陣分解的損失函數定義如下:

圖片

其中 K 為評分矩陣中已知的(u,i) 集合。例如下面的評分矩陣對應的 K為

圖片

求解上述損失函數存在兩種典型的優化方法,分別為

  • 交替最小二乘 (Alternating Least Squares, ALS)
  • 隨機梯度下降 (Stochastic Gradient Descent, SGD)

交替最小二乘,指的是固定其中一個變量,利用最小二乘求解另一個變量,以此交替進行,直至收斂或者到達最大迭代次數,這也是“交替”一詞的由來。

隨機梯度下降,是優化理論中最常用的一種方式,通過計算梯度,然后更新待求的變量。

在矩陣分解算法中,Spark最終選擇了ALS作為官方的唯一實現,原因是ALS很容易實現并行化,任務之間沒有依賴。

下面我們動手推導一下整個計算過程,在機器學習理論中,微分的單位一般在向量維度,很少去對向量的分量為偏微分推導。

首先我們固定物品矩陣 Y,將物品矩陣 Y看成常量。不失一般性,我們定義用戶u 評分過的物品集合為  IuIu,利用損失函數對向量?xuxu 求偏導,并且令導數等于0可得:

圖片

因為向量 xuxu與求和符號 ∑i∈Iu∑i∈Iu無關,所有將其移出求和符號,因為 ?xTuyiyTixuTyiyiT 是矩陣相乘 (不滿足交換性),因此 xuxu  在左邊

圖片

等式兩邊取轉置,我們有

圖片

為了化簡 ∑i∈IuyiyTi∑i∈IuyiyiT   與   ∑i∈Iuru,iyi∑i∈Iuru,iyi,我們將 ?Iu 展開。

假設Iu={ic1,?,icN} , 其中N表示用戶u評分過的物品數量,iciici表示第 cici個物品對應的索引/序號,借助于 Iu ,我們有

圖片

其中,

YIuYIu 為以?Iu={ic1,?icN}Iu={ic1,?icN} 為行號在物品矩陣 Y 中選取的N個行向量形成的子矩陣

Ru,Iu為以Iu={ic1,?icN} 為索引,在評分矩陣 R的第u 行的行向量中選取的N 個元素,形成的子行向量

因此,我們有

圖片

網上的博客,許多博主給出類似下面形式的結論不是很嚴謹,主要是損失函數的理解不到位導致的。

圖片

同理,我們定義物品 i 被評分的用戶集合為 Ui={ud1,?udM}Ui={ud1,?udM}

根據對稱性可得

圖片

其中,

?XUiXUi 為以 ?Ui={ud1,?,udM}Ui={ud1,?,udM} 為行號在用戶矩陣X中選取的M個行向量形成的子矩陣

Ri,UiRi,Ui 為以 Ui={ud1,?,udM}Ui={ud1,?,udM} 為索引,在評分矩陣 R的第i列的列向量中選取的 M個元素,形成的子列向量

此外,IkIk 為單位矩陣?

如果讀者感覺上述的推導還是很抽象,我們也給一個具體實例來體會一下中間過程

圖片

注意到損失函數是一個標量,這里我們只展開涉及到x1,1,x1,2x1,1,x1,2的項,如下所示

圖片

讓損失函數對 x1,1,x1,2x1,1,x1,2  分別求偏導數可以得到

圖片

寫成矩陣形式可得

圖片

利用我們上述的規則,很容易檢驗我們導出的結論。

總結來說,ALS的整個算法過程只有兩步,涉及2個循環,如下圖所示:

圖片

算法使用RMSE(root-mean-square error)評估誤差。

圖片

當RMSE值變化很小時或者到達最大迭代步驟時,滿足收斂條件,停止迭代。

“Talk is cheap. Show me the code.” 作為小練習,我們給出上述偽代碼的Python實現。

import numpy as np
from scipy.linalg import solve as linear_solve
# 評分矩陣 5 x 6
R = np.array([[4, 0, 2, 5, 0, 0], [3, 2, 1, 0, 0, 3], [0, 2, 0, 3, 0, 4], [0, 3, 3,5, 4, 0], [5, 0, 3, 4, 0, 0]])
m = 5 # 用戶數
n = 6 # 物品數
k = 3 # 隱向量的維度
_lambda = 0.01 # 正則化系數
# 隨機初始化用戶矩陣, 物品矩陣
X = np.random.rand(m, k)
Y = np.random.rand(n, k)
# 每個用戶打分的物品集合
X_idx_dict = {1: [1, 3, 4], 2: [1, 2, 3, 6], 3: [2, 4, 6], 4: [2, 3, 4, 5], 5: [1, 3, 4]}
# 每個物品被打分的用戶集合
Y_idx_dict = {1: [1, 2, 5], 2: [2, 3, 4], 3: [1, 2, 4, 5], 4: [1, 3, 4, 5], 5: [4], 6: [2, 3]}

# 迭代10次
for iter in range(10):
for u in range(1, m+1):
Iu = np.array(X_idx_dict[u])
YIu = Y[Iu-1]
YIuT = YIu.T
RuIu = R[u-1, Iu-1]
xu = linear_solve(YIuT.dot(YIu) + _lambda * np.eye(k), YIuT.dot(RuIu))
X[u-1] = xu
for i in range(1, n+1):
Ui = np.array(Y_idx_dict[i])
XUi = X[Ui-1]
XUiT = XUi.T
RiUi = R.T[i-1, Ui-1]
yi = linear_solve(XUiT.dot(XUi) + _lambda * np.eye(k), XUiT.dot(RiUi))
Y[i-1] = yi

最終,我們打印用戶矩陣,物品矩陣,預測的評分矩陣如下,可以看到預測的評分矩陣非常逼近原始評分矩陣。

# X
array([[1.30678487, 2.03300876, 3.70447639],
[4.96150381, 1.03500693, 1.62261161],
[6.37691007, 2.4290095 , 1.03465981],
[0.41680155, 3.31805612, 3.24755801],
[1.26803845, 3.57580564, 2.08450113]])
# Y
array([[ 0.24891282, 1.07434519, 0.40258993],
[ 0.12832662, 0.17923216, 0.72376732],
[-0.00149517, 0.77412863, 0.12191856],
[ 0.12398438, 0.46163336, 1.05188691],
[ 0.07668894, 0.61050204, 0.59753081],
[ 0.53437855, 0.20862131, 0.08185176]])
# X.dot(Y.T) 預測評分
array([[4.00081359, 3.2132548 , 2.02350084, 4.9972158 , 3.55491072, 1.42566466],
[3.00018371, 1.99659282, 0.99163666, 2.79974661, 1.98192672, 3.00005934],
[4.61343295, 2.00253692, 1.99697545, 3.00029418, 2.59019481, 3.99911584],
[4.97591903, 2.99866546, 2.96391664, 4.99946603, 3.99816006, 1.18076534],
[4.99647978, 2.31231627, 3.02037696, 4.0005876 , 3.5258348 , 1.59422188]])
# 原始評分矩陣
array([[4, 0, 2, 5, 0, 0],
[3, 2, 1, 0, 0, 3],
[0, 2, 0, 3, 0, 4],
[0, 3, 3, 5, 4, 0],
[5, 0, 3, 4, 0, 0]])

三、Spark  ALS應用

Spark的內部實現并不是我們上面所列的算法,但是核心原理是完全一樣的,Spark實現的是上述偽代碼的分布式版本,具體算法參考Large-scale Parallel Collaborative Filtering for the Netflix Prize。其次,查閱Spark的官方文檔,我們也注意到,Spark使用的懲罰函數與我們上文的有細微的差別。

圖片

其中  nu,ninu,ni分別表示用戶u打分的物品數量和物品 i 被打分的用戶數量。即

圖片

本小節通過兩個案例來了解Spark ALS的具體使用,以及在面對互聯網實際工程場景下的應用。

3.1 Demo案例

以第一節給出的數據為例,將三元組(User, Item, Rating)組織為als-demo-data.csv,該demo數據集涉及5個用戶和6個物品。

userId,itemId,rating
1,1,4
1,3,2
1,4,5
2,1,3
2,2,2
2,3,1
2,6,3
3,2,2
3,4,3
3,6,4
4,2,3
4,3,3
4,4,5
4,5,4
5,1,5
5,3,3
5,4,4

使用Spark的ALS類使用非常簡單,只需將三元組(User, Item, Rating)數據輸入模型進行訓練。

import org.apache.spark.sql.SparkSession
import org.apache.spark.ml.recommendation.ALS
val spark = SparkSession.builder().appName("als-demo").master("local[*]").getOrCreate()
val rating = spark.read
.options(Map("inferSchema" -> "true", "delimiter" -> ",", "header" -> "true"))
.csv("./data/als-demo-data.csv")
// 展示前5條評分記錄
rating.show(5)
val als = new ALS()
.setMaxIter(10) // 迭代次數,用于最小二乘交替迭代的次數
.setRank(3) // 隱向量的維度
.setRegParam(0.01) // 懲罰系數
.setUserCol("userId") // user_id
.setItemCol("itemId") // item_id
.setRatingCol("rating") // 評分列
val model = als.fit(rating) // 訓練模型
// 打印用戶向量和物品向量
model.userFactors.show(truncate = false)
model.itemFactors.show(truncate = false)
// 給所有用戶推薦2個物品
model.recommendForAllUsers(2).show()

上述代碼在控制臺輸出結果如下:

+------+------+------+
|userId|itemId|rating|
+------+------+------+
| 1| 1| 4|
| 1| 3| 2|
| 1| 4| 5|
| 2| 1| 3|
| 2| 2| 2|
+------+------+------+
only showing top 5 rows
+---+------------------------------------+
|id |features |
+---+------------------------------------+
|1 |[-0.17339179, 1.3144133, 0.04453602]|
|2 |[-0.3189066, 1.0291641, 0.12700711] |
|3 |[-0.6425665, 1.2283803, 0.26179287] |
|4 |[0.5160747, 0.81320006, -0.57953185]|
|5 |[0.645193, 0.26639006, 0.68648624] |
+---+------------------------------------+
+---+-----------------------------------+
|id |features |
+---+-----------------------------------+
|1 |[2.609607, 3.2668495, 3.554771] |
|2 |[0.85432494, 2.3137972, -1.1198239]|
|3 |[3.280517, 1.9563107, 0.51483333] |
|4 |[3.7446978, 4.259611, 0.6640027] |
|5 |[1.6036265, 2.5602736, -1.8897828] |
|6 |[-1.2651576, 2.4723763, 0.51556784]|
+---+-----------------------------------+
+------+--------------------------------+
|userId|recommendations |
+------+--------------------------------+
|1 |[[4, 4.9791617], [1, 3.9998217]]| // 對應物品的序號和預測評分
|2 |[[4, 3.273963], [6, 3.0134287]] |
|3 |[[6, 3.9849386], [1, 3.2667015]]|
|4 |[[4, 5.011649], [5, 4.004795]] |
|5 |[[1, 4.994258], [4, 4.0065994]] |
+------+--------------------------------+

我們使用numpy來驗證Spark的結果,并且用Excel可視化評分矩陣。

import numpy as np
X = np.array([[-0.17339179, 1.3144133, 0.04453602],
[-0.3189066, 1.0291641, 0.12700711],
[-0.6425665, 1.2283803, 0.26179287],
[0.5160747, 0.81320006, -0.57953185],
[0.645193, 0.26639006, 0.68648624]])
Y = np.array([[2.609607, 3.2668495, 3.554771],
[0.85432494, 2.3137972, -1.1198239],
[3.280517, 1.9563107, 0.51483333],
[3.7446978, 4.259611, 0.6640027],
[1.6036265, 2.5602736, -1.8897828],
[-1.2651576, 2.4723763, 0.51556784]])
R_predict = X.dot(Y.T)
R_predict

輸出預測的評分矩陣如下:

array([[3.99982136, 2.84328038, 2.02551472, 4.97916153, 3.0030386,  3.49205357],
[2.98138452, 1.96660155, 1.03257371, 3.27396294, 1.88351875, 3.01342882],
[3.26670123, 2.0001004 , 0.42992289, 3.00003605, 1.61982132, 3.98493822],
[1.94325135, 2.97144913, 2.98550149, 5.011649 , 4.00479503, 1.05883274],
[4.99425778, 0.39883335, 2.99113433, 4.00659955, 0.41937014, 0.19627587]])

從Excel可視化的評分矩陣可以觀察到預測的評分矩陣非常逼近原始的評分矩陣,以user-3為例,Spark推薦的物品是item-6和item-1, [[6, 3.9849386], [1, 3.2667015]],這和Excel展示的預測評分矩陣完全一致。

從Spark函數recommendForAllUsers()給出的結果來看,Spark內部并沒有去除用戶已經購買的物品。

圖片

3.2 工程應用

在互聯網場景,用戶數 m(千萬~億級別) 和物品數 n (10萬~100萬級別) 規模很大,App的埋點數據一般會保存在HDFS中,以互聯網的長視頻場景為例,用戶的埋點信息最終聚合為用戶行為表  t_user_behavior。

行為表包含用戶的imei,物品的content-id,但是沒有直接的用戶評分,實踐中我們的解決方案是利用用戶的其他行為進行加權得出用戶對物品的評分。即

rating = w1 * play_time (播放時長) + w2 * finsh_play_cnt (完成的播放次數) + w3 * praise_cnt (點贊次數) + w4 * share_cnt (分享次數) + 其他適合于你業務邏輯的指標

其中, wi為每個指標對應的權重。

圖片

如下的代碼塊演示了工程實踐中對大規模用戶和商品場景進行推薦的流程。

import org.apache.spark.ml.feature.{IndexToString, StringIndexer}
// 從hive加載數據,并利用權重公式計算用戶對物品的評分
val rating_df = spark.sql("select imei, content_id, 權重公式計算評分 as rating from t_user_behavior group by imei, content_id")
// 將imei和content_id轉換為序號,Spark ALS入參要求userId, itemId為整數
// 使用org.apache.spark.ml.feature.StringIndexer
val imeiIndexer = new StringIndexer().setInputCol("imei").setOutputCol("userId").fit(rating_df)
val contentIndexer = new StringIndexer().setInputCol("content_id").setOutputCol("itemId").fit(rating_df)
val ratings = contentIndexer.transform(imeiIndexer.transform(rating_df))
// 其他code,類似于上述demo
val model = als.fit(ratings)
// 給每個用戶推薦100個物品
val _userRecs = model.recommendForAllUsers(100)
// 將userId, itemId轉換為原來的imei和content_id
val imeiConverter = new IndexToString().setInputCol("userId").setOutputCol("imei").setLabels(imeiIndexer.labels)
val contentConverter = new IndexToString().setInputCol("itemId").setOutputCol("content_id").setLabels(contentIndexer.labels)
val userRecs = imeiConverter.transform(_userRecs)
// 離線保存供線上調用
userRecs.foreachPartition {
// contentConverter 將itemId轉換為content_id
// 保存redis邏輯
}

值得注意的是,上述的工程場景還有一種解決方案,即隱式反饋。用戶給商品評分很單一,在實際的場景中,用戶未必會給物品打分,但是大量的用戶行為,同樣能夠間接反映用戶的喜好,比如用戶的購買記錄、搜索關鍵字,加入購物車,單曲循環播放同一首歌。我們將這些間接用戶行為稱之為隱式反饋,以區別于評分對應的顯式反饋。胡一凡等人在論文Collaborative filtering for implicit feedback datasets中針對隱式反饋場景提出了ALS-WR模型  (ALS with Weighted-λ-Regularization),并且Spark官方也實現了該模型,我們將在以后的文章中介紹該模型。

四、總結

本文從推薦的場景出發,引出了協同過濾這一經典的推薦算法,并且由此講解了被Spark唯一實現和維護的矩陣分解算法,詳細推導了顯示反饋下矩陣分解的理論原理,并且給出了Python版本的單機實現,能夠讓讀者更好的理解矩陣這一算法,最后我們以demo和工程實踐兩個實例講解了Spark ALS的使用,能夠讓沒有接觸過推薦算法的同學有個直觀的理解,用理論與實踐的形式明白矩陣分解這一推薦算法背后的原理。

參考文獻:

  1. 王喆, 深度學習推薦系統
  2. Hu, Yifan, Yehuda Koren, and Chris Volinsky. "Collaborative filtering for implicit feedback datasets." 2008 Eighth IEEE International Conference on Data Mining. IEEE, 2008.
  3. Zhou, Yunhong, et al. "Large-scale parallel collaborative filtering for the Netflix prize." International conference on algorithmic applications in management. Springer, Berlin, Heidelberg, 2008.

責任編輯:未麗燕 來源: vivo互聯網技術
相關推薦

2017-02-05 21:02:44

大數據深度學習推薦系統

2017-04-27 18:09:26

item embedd推薦系統算法

2023-10-31 16:46:45

2020-06-28 07:30:00

推薦算法推薦系統

2016-08-18 01:36:14

協同過濾推薦電影用戶

2021-11-15 12:45:44

協同過濾算法架構

2024-03-11 08:00:00

位置偏差算法矩陣分解算法

2017-02-08 09:25:16

Spark分解推薦

2018-05-21 08:22:14

自編碼器協同過濾深度學習

2024-02-05 09:30:10

推薦算法深度學習內容過濾

2018-03-23 11:33:56

協同過濾程序算法

2024-07-23 08:00:00

2024-10-29 09:00:00

2019-05-05 09:00:00

數據分析算法推薦系統

2025-10-09 02:55:00

SpringBoot短視頻向量搜索

2020-06-29 07:00:00

推薦算法推薦系統

2022-10-14 08:03:46

圖形數據庫系統

2017-06-29 09:15:36

推薦算法策略

2024-06-26 19:18:53

2018-03-23 11:56:09

相似性推薦推薦算法推薦
點贊
收藏

51CTO技術棧公眾號

欧美精品二区三区| 少妇愉情理伦片bd| av网在线观看| 国产伦精品一区二区三区免费迷| 欧美成年人视频网站欧美| 亚洲最大视频网| 日韩欧美看国产| ●精品国产综合乱码久久久久| 成人在线观看av| 超碰在线观看91| 欧美日本中文| 影音先锋日韩有码| 亚洲成年人在线观看| 精品裸体bbb| 午夜精品一区二区三区电影天堂 | 亚洲+小说+欧美+激情+另类 | 99热一区二区| 男人久久天堂| 亚洲一区二区三区中文字幕 | 欧美军同video69gay| 亚洲熟妇无码一区二区三区导航| 日本美女高潮视频| 日韩美女网站| 久久色.com| a级国产乱理论片在线观看99| 青青草视频在线观看免费| 国产精品www.| 久久这里有精品视频| 美女被到爽高潮视频| 国产一级成人av| 日韩欧美三级在线| 日本黄大片一区二区三区| 爱情电影社保片一区| 亚洲不卡一区二区三区| 异国色恋浪漫潭| 国产黄色在线| 久久日一线二线三线suv| 国产精品一区二| 精品黑人一区二区三区国语馆| 日韩国产欧美视频| 日本免费久久高清视频| 国产区一区二区三| 中文亚洲字幕| 午夜美女久久久久爽久久| 麻豆疯狂做受xxxx高潮视频| 我不卡伦不卡影院| 久久久极品av| 人妻少妇精品一区二区三区| 一区二区影院| 久久久国产成人精品| 色www亚洲国产阿娇yao| 色综合蜜月久久综合网| 中文字幕免费精品一区高清| 日本少妇xxxxx| 国产一区二区三区四区| 国产亚洲精品久久久久动| b站大片免费直播| 精品国产乱码久久久久久蜜坠欲下| 精品网站999www| 毛片网站免费观看| 红桃成人av在线播放| 中文字幕亚洲欧美日韩在线不卡| 一级特黄曰皮片视频| 日韩综合精品| www.日韩不卡电影av| 永久免费未视频| 欧美a级片网站| 欧美激情一级二级| 久久国产精品免费看| 日日嗨av一区二区三区四区| 国产精品一区二区久久国产| 国产精品爽爽久久| 成人精品电影在线观看| 久久艳妇乳肉豪妇荡乳av| 国外av在线| 1024精品合集| 奇米精品一区二区三区| gogo亚洲高清大胆美女人体| 欧美裸体一区二区三区| ass极品水嫩小美女ass| 噜噜噜天天躁狠狠躁夜夜精品 | 久久电影视频| 中文无字幕一区二区三区| 三年中国中文在线观看免费播放| 国产精品—色呦呦| 日韩欧美中文字幕在线观看| 亚洲欧美日韩一级| 哺乳一区二区三区中文视频 | 天堂蜜桃一区二区三区| 成人久久一区二区| 色婷婷av一区二区三区之e本道| 国产日韩v精品一区二区| 超碰在线免费观看97| 韩日毛片在线观看| 在线成人免费观看| 精品无码在线视频| 手机在线电影一区| 久久久久中文字幕2018| 最新中文字幕在线观看视频| 国产成人精品亚洲777人妖 | 激情久久久久| 国产精品久久久一区| 丰满肉肉bbwwbbww| 国产精品伦一区二区三级视频| 无码熟妇人妻av在线电影| 外国电影一区二区| 精品88久久久久88久久久| 丰满的亚洲女人毛茸茸| 在线观看视频日韩| 91麻豆桃色免费看| 高清性色生活片在线观看| 亚洲午夜影视影院在线观看| 亚洲欧美视频二区| 九九在线高清精品视频| 韩剧1988免费观看全集| 国产女主播福利| 日本一区二区免费在线| 日韩欧美视频网站| 亚洲无线观看| 欧美精品生活片| 中文字幕人妻一区二区在线视频 | 国产成人免费av在线| 一本一道久久a久久综合精品| 忘忧草在线影院两性视频| 日韩精品一区二区三区视频在线观看| 日韩不卡av在线| 久久久综合网| 美脚丝袜一区二区三区在线观看| 成人影院在线播放| 日韩午夜激情免费电影| 亚洲熟女少妇一区二区| 日韩中文字幕麻豆| 欧美xxxx黑人又粗又长密月 | 国产精品影片在线观看| 黄色片视频在线观看| 欧美日韩国产一区二区三区| 中国黄色片视频| 欧美日韩视频| 99在线看视频| 人人超在线公开视频| 欧美一级视频精品观看| 国产性xxxx| 国产成人h网站| 国产91porn| 亚洲精品观看| 欧美精品久久久久久久| 粉嫩av一区二区夜夜嗨| 亚洲一区中文日韩| 丰满饥渴老女人hd| 欧美三级免费| 国产日本一区二区三区| 精品人人视频| 亚洲人av在线影院| 色老头在线视频| 中文字幕不卡在线| 亚洲天堂国产视频| 亚洲男女av一区二区| 91亚洲精品丁香在线观看| 日韩经典av| 亚洲精品动漫100p| 天天爽夜夜爽人人爽| 国产欧美视频一区二区三区| 992kp快乐看片永久免费网址| 欧美成人精品一区二区三区在线看| 国产日本欧美一区二区三区| 99热国产在线| 亚洲第一福利视频| 中文字幕av影院| 国产精品久久毛片av大全日韩| 亚洲欧美日本一区二区三区| 欧美激情日韩| 麻豆传媒一区| 成人在线视频国产| 高清一区二区三区日本久| 青青草免费在线视频| 欧美日本国产视频| 国产精品suv一区二区| 国产视频不卡一区| 国产乱叫456| 在线观看的日韩av| 亚洲精品高清国产一线久久| 精品国产鲁一鲁****| 97avcom| www.亚洲视频| 欧美第一区第二区| 亚洲国产成人精品女人久久| 亚洲私人影院在线观看| 性欧美18—19sex性高清| 老司机午夜免费精品视频 | 亚洲精品色图| 亚洲国产精品一区二区第一页 | 一区二区三区四区国产| 懂色av一区二区| 国产精品自拍网| 成人国产电影在线观看| 色阁综合伊人av| 特黄视频在线观看| 欧美精品一级二级三级| 在线观看国产亚洲| 亚洲少妇中出一区| 在哪里可以看毛片| 国产iv一区二区三区| 美女网站色免费| 中文日韩欧美| 日韩成人手机在线| 欧美激情黄色片| 欧美日韩一区二区三区在线视频| 国产一区二区在线观| 国产成人久久久| 涩涩在线视频| 欧美国产精品va在线观看| 香蕉视频免费在线播放| 精品亚洲一区二区| 丰满人妻av一区二区三区| 欧美日韩精品一区二区天天拍小说| 久久不卡免费视频| 一区二区三区美女| 91大神福利视频| 欧美国产国产综合| 亚洲午夜福利在线观看| av在线播放成人| 一区二区在线免费观看视频| 久久99国内精品| 黄色片在线免费| 久久性天堂网| 久久久999视频| 黄色一区二区三区四区| 青青草视频国产| 亚洲精品成人无限看| 亚洲7777| 欧美亚洲国产激情| 色噜噜一区二区| 欧美码中文字幕在线| 欧美美乳视频网站在线观看| 秋霞影视一区二区三区| 国产伦精品一区二区三区视频黑人 | 91精品国偷自产在线电影| 亚洲高清不卡一区| 久久精品国产www456c0m| 日韩性感在线| 大片网站久久| 亚洲午夜精品久久久中文影院av | 日韩中文字幕在线免费观看| 不卡在线视频| 精品国产一区二区三区久久| 免费看美女视频在线网站| 日韩一区二区欧美| 素人av在线| 久久亚洲国产成人| 在线观看av免费| 久久理论片午夜琪琪电影网| 国产精品一二三产区| 97超视频免费观看| 电影网一区二区| 国产精品久久久久久久电影| 成人在线视频观看| 92国产精品久久久久首页 | 久久精品99国产国产精| 182午夜视频| 国产99久久久久| 国产福利在线观看视频| 久久综合网色—综合色88| 国产精品国产三级国产专业不 | 亚洲欧美精品一区二区| 国产美女性感在线观看懂色av | 日本精品在线免费观看| 亚洲美女在线国产| 日干夜干天天干| 91精品1区2区| 中文字幕在线观看第二页| 5月丁香婷婷综合| 日韩专区第一页| 国产午夜精品一区二区三区| 国产福利视频在线| 午夜精品一区二区三区av| 日韩av首页| 91精品国产综合久久久久久丝袜 | 亚洲一卡二卡区| 欧美日韩三级| mm1313亚洲国产精品无码试看| 美女网站色91| 少妇被狂c下部羞羞漫画| 国产视频视频一区| 欧美日韩国产精品一区二区三区| 精品国产户外野外| 91精品国产乱码久久| 精品国产一区二区精华| 精品美女视频在线观看免费软件 | 97精品国产露脸对白| 国产7777777| 亚洲成精国产精品女| 中文在线观看免费高清| 精品乱码亚洲一区二区不卡| 国产剧情在线观看| 欧美精品18videos性欧美| 写真福利精品福利在线观看| 官网99热精品| 久久精品国产99久久| 美女av免费在线观看| 国产精品中文欧美| 一级片视频免费看| 亚洲国产精品综合小说图片区| 亚洲一区二区色| 精品视频在线导航| 黑人玩欧美人三根一起进| 国产精品入口免费视频一| 群体交乱之放荡娇妻一区二区| 天天爱天天做天天操| 蜜臀av性久久久久蜜臀aⅴ| 无码人妻aⅴ一区二区三区 | www.亚洲免费视频| 97成人资源| 国产欧美日韩视频一区二区三区| 中文精品电影| 美女网站视频黄色| www成人在线观看| 久久免费视频播放| 欧美疯狂性受xxxxx喷水图片| 激情综合闲人网| 欧美主播福利视频| 国产精品毛片av| 黄色一级大片免费| 国产一区二区三区四| 国产视频123区| 欧美亚洲高清一区二区三区不卡| 亚洲 欧美 激情 小说 另类| 欧美精品久久久久久久| 91成人午夜| 妺妺窝人体色www看人体| 国产制服丝袜一区| 国产精品视频一区二区在线观看| 欧美性大战久久久久久久| 久久视频www| 全亚洲最色的网站在线观看| 国产伦精品一区二区三区在线播放| 中文字幕色呦呦| 国产高清精品久久久久| 在线观看美女av| 欧美一区二区免费视频| 久久77777| 91青青草免费观看| 欧美日韩网址| 亚洲欧美日韩偷拍| 香港成人在线视频| 污污网站在线免费观看| 97免费视频在线播放| 色老板在线视频一区二区| 无码aⅴ精品一区二区三区浪潮 | 极品美鲍一区| 九9re精品视频在线观看re6 | 午夜一区二区视频| 亚洲人妖av一区二区| 国产成人免费看一级大黄| 欧美激情精品久久久久久大尺度| 9l视频自拍蝌蚪9l视频成人| 国产亚洲黄色片| 久久欧美一区二区| 国产又粗又猛又黄视频| 日韩在线免费高清视频| 久久久久毛片免费观看| 国产九色porny| 久久久久久电影| 中文字幕在线日亚洲9| 久久亚洲国产精品成人av秋霞| 日韩第一区第二区| 欧美一区二区中文字幕| 国产人成一区二区三区影院| 97视频免费在线| 午夜精品久久久久久99热软件| 亚洲+变态+欧美+另类+精品| 我要看一级黄色大片| 亚洲欧美日韩在线| 亚州男人的天堂| 国产精品女视频| 黄色亚洲精品| 高清国产在线观看| 日韩一区二区三区在线| 老司机深夜福利在线观看| 亚洲欧美在线网| 成人免费视频视频| 中文字幕乱码在线观看| 欧美激情亚洲自拍| 欧美日韩国产免费观看视频| 中文写幕一区二区三区免费观成熟| 精品二区三区线观看| 91xxx在线观看| 国产视频在线观看一区| 奇米精品一区二区三区在线观看一 | 日韩美女在线看| 真实国产乱子伦精品一区二区三区| 日本黄色动态图| 7777精品伊人久久久大香线蕉经典版下载 | 国产精品美女一区二区在线观看| 亚洲欧美激情另类| 国产日韩一区在线| 国产欧美午夜| 日韩一级片av| xvideos成人免费中文版| 美女一区2区| 极品人妻一区二区|