1. 程式人生 > 其它 >讓你又愛又恨的推薦系統--程式猿篇

讓你又愛又恨的推薦系統--程式猿篇

又愛又恨的推薦系統

作為一名程式猿,一直對推薦系統比較感興趣,最近看到一個使用者的吐槽:

又愛又恨

推薦系統的應用場景,我相信在日常生活中大家基本都會接觸到。例如,作為一個籃球愛好者,在淘寶上搜索的“kobe X 籃球鞋”,然後之後一段時間開啟淘寶,首頁介面可能會推薦很多與籃球鞋相關的商品,這算是一個比較正常的應用場景吧。當然還可能有其它的一些場景,例如上面使用者吐槽的手機麥克風可能被監控,進而自己的喜好被平臺方獲取併產生推薦......

一個好的推薦系統不可避免的需要準確、儘可能詳細的瞭解目標使用者的喜好特徵,有時候不經意間觸碰到使用者的隱私,這可能會引起使用者的牴觸情感。

但是,一個好的推薦系統又是被使用者所推崇喜愛的,例如:網易雲音樂,它的歌單推薦功能,我相信這是很多使用網易音樂的使用者選擇這款音樂應用的重要原因之一。

至於,如何平衡保護使用者隱私與實現推薦系統功能,我認為這就需要平臺方與使用者有充分的互動與信任,平臺有義務向用戶透明應用會獲取的使用者資訊,使用者有權利保護個人不想透露的隱私資訊。

畢竟,一個優秀的推薦系統是應該能夠讓使用者與平臺方實現雙贏的局面。

以上,是一個程式猿的淺薄見解,還是做回老本行,介紹一下推薦系統的基礎技術吧!

為什麼需要推薦系統

如今,我們這代人正經歷從資訊時代(Information Technology,IT)到資料時代(Data Technology,DT)的變遷,DT時代比較明顯的標誌就是:資訊過載。

羅胖2017跨年演講

在DT時代,充斥著海量的資訊,如何從海量的資訊中快捷的幫助特定使用者找到感興趣的資訊呢?有兩種相關的解決技術:搜尋引擎與推薦系統。

搜尋引擎與推薦系統有什麼區別? 搜尋引擎:實現人找資訊,eg.百度搜索... 推薦系統:實現資訊找人,eg.亞馬遜的圖書推薦列表...

與搜尋引擎不同,推薦系統不需要使用者準確地描述出自己的需求,而是根據分析歷史行為建模,主動提供滿足使用者興趣和需求的資訊。

亞馬遜商城

由此,可見推薦系統關注的是如何主動的為需求尚未明確的使用者,推薦他們可能感興趣的資訊。

例如,消費者如何不經意間發現自己喜歡的商品,生產者以及平臺方如何讓自己的商品脫穎而出,增加銷量,挖掘商品’長尾’…..推薦系統就是為了解決這些問題的。

簡單來說,對於消費者而言,他們喜歡用2個小時去看一部感興趣的電影,卻不願意花20分鐘去挑選,這就是個性化推薦系統存在的意義。

什麼是推薦系統

推薦系統通過分析、挖掘使用者行為,發現使用者的個性化需求與興趣特點,將使用者可能感興趣的資訊或商品推薦給使用者。一個優秀的推薦系統,能夠很好的串聯起使用者、商家以及平臺方,並讓三方都收益。

推薦系統

本質上來講,推薦系統就是對所有商品針對特定使用者進行按照一定策略進行排序,然後篩選出若干商品推薦給使用者的過程。

2.1、傳統的推薦系統方法主要有:

1、協同過濾推薦(Collaborative Filtering Recommendation):該方法收集分析使用者歷史行為、活動、偏好,計算一個使用者與其他使用者的相似度,利用目標使用者的相似使用者對商品評價的加權評價值,來預測目標使用者對特定商品的喜好程度。優點是可以給使用者推薦未瀏覽過的新產品;缺點是對於沒有任何行為的新使用者存在冷啟動的問題,同時也存在使用者與商品之間的互動資料不夠多造成的稀疏問題,會導致模型難以找到相近使用者。

2、基於內容過濾推薦[1](Content-based Filtering Recommendation):該方法利用商品的內容描述,抽象出有意義的特徵,通過計算使用者的興趣和商品描述之間的相似度,來給使用者做推薦。優點是簡單直接,不需要依據其他使用者對商品的評價,而是通過商品屬性進行商品相似度度量,從而推薦給使用者所感興趣商品的相似商品;缺點是對於沒有任何行為的新使用者同樣存在冷啟動的問題。

3、組合推薦[2](Hybrid Recommendation):運用不同的輸入和技術共同進行推薦,以彌補各自推薦技術的缺點。

協同過濾推薦

基於協同過濾推薦演算法的思想是:通過對使用者歷史行為資料的挖掘發現使用者的偏好,基於不同的偏好對使用者進行群組劃分並推薦品味相似的項。在計算推薦結果的過程中,不依賴於項的任何附加資訊或者使用者的任何附加資訊,只與使用者對項的評分有關。

資料集構成

通常有兩種方法:

1、通過相似使用者進行推薦。通過比較使用者之間的相似性,越相似表明兩者之間的品味越相近,這樣的方法被稱為基於使用者的協同過濾演算法(User-based Collaborative Filtering);

2、通過相似項進行推薦。通過比較項與項之間的相似性,為使用者推薦與評價過的項的相似項,這樣的方法被稱為基於項的協同過濾演算法(Item-based Collaborative Filtering)。

基於使用者的:User-based Collaborative Filtering,為使用者推薦和他興趣相似的使用者喜歡的商品。

基於項(商品)的:tem-based Collaborative Filtering,為使用者推薦與他之前喜歡的商品相似度高的商品.

這個演算法的核心,就是如何衡量使用者與使用者之間的相似度或者商品與商品之間的相似度。

相似性的度量方法有很多種,比如:歐式距離、皮爾森相關係數、餘弦相似度等。

歐式距離是使用的比較多的相似性度量方法,其用歐式距離作為樣本之間的相似性的度量,但是在歐式距離的計算中,不同特徵之間的量級對歐式距離的影響比較大,但是皮爾森相關係數對量級不敏感。

餘弦相似度是文字相似度中使用較多的一種方法。後面我們主要介紹餘弦相似度。

3.1、基於使用者的與基於商品的推薦方法區別

1、UserCF: 看重使用者相似的小群體的熱點,偏重社會化,一般適用於新聞推薦

改進:UserCF-IIF:(類似於TF-IDF的作用):實際業務中使用者數量太多,很難對推薦結果做出解釋。

2、ItemCF: 看重個性化,反應使用者個人興趣的傳承性,此外商品的更新不能太快,因為實時計算物品相似度矩陣非常耗時,這也是為啥新聞一般不用ItemCF。

ItemCF在實際業務中用的比較多,可以基於使用者的歷史購買商品行為對推薦結果做出可理解的解釋。

同時,從技術上考慮,UserCF需要維護一個使用者相似度的矩陣,而ItemCF需要維護一個物品 相似度矩陣。從儲存的角度說,如果使用者很多,那麼維護使用者興趣相似度矩陣需要很大的空間, 同理,如果物品很多,那麼維護物品相似度矩陣代價較大。

來自<<推薦系統>>

ItemCF的計算過程主要分為兩步:

1、計算物品之間的相似度。【對相似度矩陣按最大值進行歸一化可以提高推薦的準確率、覆蓋率、多樣性】

2、根據物品相似度和該使用者的歷史行為為該使用者產生推薦列表【排序】。

[文章末尾有一份Python實現的Demo]

商品相似度矩陣計算

為特點使用者產生推薦列表

該演算法的弊端:

這個演算法實現起來比較簡單,但是在實際應用中會存在一定的問題。

比如一些非常流行的商品可能很多人都喜歡,這種商品推薦給你就沒什麼意義了,所以計算的時候需要對這種商品加一個權重或者把這種商品去掉。對於一些通用的東西,比如工具書,洗衣液等通用性太強了,推薦也沒什麼必要了。這些都是推薦系統的髒資料。

此外,當新使用者出現時,我們對其興趣愛好一無所知,這時如何做出推薦是一個很重要的問題。一般在這個時候,我們只是向用戶推薦那些普遍反應比較好的物品,也就是說,推薦完全是基於物品的。還有,不是所有的使用者都對很多商品給出了評分,很多使用者只給少數的書給出了評分,如何處理那些不太表露自己興趣的使用者,也是推薦系統的一個主要問題。

工業界的推薦系統

推薦系統在工業界具有廣泛的應用,相關的職位招聘也是比較多,算是機器學習相關職位中需求比較多的方向之一。曾經接觸過兩個網際網路企業的推薦系統相關的工作,也算感觸到工業界與學術界的一些區別,下面是我自己的一些感觸與見聞。

1、資料量

企業級的資料一般都是G量級起步的資料量,很難使用我們參加一些小型競賽的資料處理方式,python的Pandas等庫一般使用很難操作這些業務資料,所以很多推薦系統都是搭建在叢集之上的,資料儲存可能是基於Hadoop的HDFS等,計算框架一般是Spark或者企業自研的資料平臺(阿里的PAI平臺...主要任務就是寫SQL...羨慕吧)。所以,入職的第一步就是學習hadoop平臺與spark的使用,所以,現在後悔上學的時候沒有好好的學這些東西啊。

企業級推薦系統

2、實際業務理解

不同的業務場景需要我們根據實際的業務資料深挖資料背後的隱藏資訊,大的推薦系統部門,一般都是按照業務部門劃分不同的推薦小組,並且推薦小組內有的還會進一步細分任務,例如有專門的基礎平臺小組、負責召回的、負責排序的。業務邏輯也是需要不斷的迭代的,一般每一個工程師每週基本都會上線新的策略,根據實際上線後的效果,不斷進行迭代開發。

美圖大眾點評

3、如何合理的評價推薦系統效果?

參加過一些資料競賽的推薦系統,一般平臺會給出一個評價函式,可能是準確率、召回率等常見評價函式的調和函式。但在實際的業務場景中,卻很難給出一個準確的評價函式來評價我們推薦系統的效果。這其中就涉及到推薦系統中多樣性與精確性的兩難困境

如果要給使用者推薦他喜歡的商品,最“保險”的方式就是給他特別流行或者得分特別高的商品,因為這些爆款商品有更可能被喜歡,往壞了說,也很難特別被討厭。但這種推薦產生的使用者體驗並不一定好,因為使用者很可能已經知道這些熱銷或流行的產品,所以得到的資訊量很少,並且使用者不會認為這是 一種“個性化”推薦。

事實上,Mcnee等人已經警告大家,盲目崇拜精確性指標可能會傷害推薦系統,因為這樣可能會導致使用者得到一些資訊量為0的“精準推薦”並且視野變得越來越狹窄。讓使用者視野變得狹窄是協同過濾演算法的一個主要缺陷,這會進一步加劇長尾效應。與此同時,應用個性化推薦技術的商家,也希望推薦中有更多的品類出現,從而激發使用者新的購物需求。

遺憾的是,推薦多樣的商品和新穎的商品與推薦的精確性之間存在矛盾,因為前者風險很大—推薦一個沒人看過或者打分較低的東西,很可能被使用者憎惡,從而效果更差。很多時候,這是一個兩難的問題,只能通過犧牲多樣性來提高精確性,或者犧牲精確性來提高多樣性。一種可行之策是直接對推薦列表進行處理,從而提升其多樣性。這種方法固然在應用上是有效的,但沒有任何理論的基礎和優美性可言,只能算一種實用的招數。

一般我們認為,精巧混合精確性高和多樣性好的兩種演算法,可以同時提高演算法的多樣性和精確性,不需要犧牲任何一方。遺憾的是,還沒有辦法就這個結果提供清晰的解讀和深刻的見解。多樣性和精確性之間錯綜複雜的關係和隱匿其後的競爭,到目前為止還是一個很棘手的難題。

朱鬱筱和呂琳媛撰寫的《推薦系統評價綜述》一文幾乎總結了文獻中曾經出現過的所有推薦系統指標,這些指標都是基於資料本身的指標,可以認為是第一層次。實際上,在真實應用時,更為重要的是另外兩個層次的評價。第二個層次是商業應用上的關鍵表現指標,如受推薦影響的轉化率、購買率、客單價、購買品類數等。第三個層次是使用者真實的體驗。

絕大部分研究只針對第一個層次的評價指標,而業界真正感興趣的是第二個層次的評價(比如,到底是哪個指標或者哪些指標組合的結果能夠提高使用者購買的客單價),而第三個層次最難,沒人能知道,只能通過第二層次來估計。因此,如何建立第一層次和第二層次指標之間的關係,就成為了關鍵。這一步打通了,理論和應用之間的屏障就通一大半了。

基於深度學習的推薦系統

其實,上面所講協同過濾的方法是一種比較傳統的方式,仍舊在工業界具有廣泛的應用。如今,伴隨著機器學習的興起了非常多的技術被應用到推薦系統中,從傳統的機器學習方式LR、GBDT、XGBoost到LightGBM,深度學習從最初利用word2vec用於評估使用者的相似度,到CNN、RNN等模型也開始被很多的推薦小組嘗試。

愛奇藝的推薦排序技術變遷

深度學習具有優秀的自動提取特徵的能力,能夠學習多層次的抽象特徵表示,並對異質或跨域的內容資訊進行學習,可以一定程度上處理推薦系統冷啟動問題。

YouTube視訊的融合推薦模型

在融合推薦模型的電影推薦系統中:

1、首先,使用使用者特徵和電影特徵作為神經網路的輸入,其中:

2、使用者特徵融合了四個屬性資訊,分別是使用者ID、性別、職業和年齡。

3、電影特徵融合了三個屬性資訊,分別是電影ID、電影型別ID和電影名稱。

4、對使用者特徵,將使用者ID對映為維度大小為256的向量表示,輸入全連線層,並對其他三個屬性也做類似的處理。然後將四個屬性的特徵表示分別全連線並相加。

5、對電影特徵,將電影ID以類似使用者ID的方式進行處理,電影型別ID以向量的形式直接輸入全連線層,電影名稱用文字卷積神經網路得到其定長向量表示。然後將三個屬性的特徵表示分別全連線並相加。

6、得到使用者和電影的向量表示後,計算二者的餘弦相似度作為推薦系統的打分。最後,用該相似度打分和使用者真實打分的差異的平方作為該回歸模型的損失函式。

融合推薦模型

現在身處工業界,最基礎的就是使用協同過濾配合其它的一些排序方法,例如GBDT,基本就能完成推薦的基本功能,基於深度學習的方式現在應用的還沒有那麼成熟,希望自己今後也能有業務需要我深入的研究一下如何在實際的業務場景中大規模的使用深度學習的推薦系統,畢竟現在我還是一個推薦系統的菜鳥,此外,一直很想寫一下對word2vec的認識與理解,關於它在推薦中的應用就留到以後的文章裡再介紹吧。

補充:一段協同過濾的Pyhton版Demo[便於理解計算的流程]

# coding:utf-8

from __future__ import division import numpy as np

from math import *

# 第一種計算相似度:餘弦相似度, 計算兩者之間相似度【計算相似度的方法有很多,這裡使用餘弦相似度】

def cos_sim(x, y): """ :param x(mat): 行向量,可以是使用者或商品 :param y(mat): 行向量,可以是使用者或商品 :return: x 和 y 之間的餘弦相似度 """ # x 與 y 之間的內積 inner_product = x * y.T norm = np.sqrt(x * x.T) * np.sqrt(y * y.T)

# 餘弦相似度的結果 return (inner_product / norm)[0, 0]

def similarity(data): """ :param data: 矩陣 :return: w(mat): 任意兩行之間的相似度,相似度矩陣w是一個對稱矩陣。在相似度矩陣中約定自身相似度為0。 """ # 使用者/商品【行數決定方陣的維度】 m =np.shape(data)[0]

# 初始化相似度矩陣 w =np.mat(np.zeros((m, m)))

for i in range(m):

for j in range(i, m):

if j != i:

# 計算兩行之間的相似度[使用者-使用者 或者 商品-商品] w[i, j] = cos_sim(data[i], data[j]) w[j, i] = w[i, j]

else: w[i, j] = 0 return w

# 第二種計算相似度:對數似然函式

def obtainK(a,b): k11=0 k12=0 k21=0 k22=0 for i in xrange(len(a)):

if a[i]==b[i]!=0: k11 +=1 if a[i]==b[i]==0: k22 +=1 if a[i]!=0 and b[i]==0: k12 +=1 if a[i]==0 and b[i]!=0: k21 +=1 return k11,k12,k21,k22

def Entropy(*x): sum=0.0 for i in x: sum +=i result=0.0 for j in x:

if j<0:

pass pinghua=1 if j==0 else 0 result += j*log((j+pinghua)/sum)

return result

def loglikelihood(N,a,b): k11,k12,k21,k22 = obtainK(a, b) rowEntropy=Entropy(k11,k12)+Entropy(k21,k22) colEntropy= Entropy(k11,k21)+Entropy(k12,k22) matEntropy=Entropy(k11,k12,k21,k22) sim=-2*(matEntropy-colEntropy-rowEntropy)

return sim

# 基於使用者的協同過濾

def user_based_recommend(data, w, user): """ :param data(mat): 使用者商品矩陣 :param w(mat): 使用者相似度矩陣 :param user(int): 使用者編號 :return: predict(list): 推薦列表 """ # m是使用者,n是商品數 m, n = np.shape(data)

# 用user這一行:商品資訊 user_product = data[user, ]

print "用user的買過商品資訊:",user_product,m,n

# 用user0的商品資訊: [[4 3 0 5 0]],這說明只有商品3,商品5他沒買過 # 找到使用者user沒有打分的商品,這是候選的推薦項 not_score = []

for i in range(n):

if user_product[0, i] == 0: not_score.append(i)

# 對沒有打分的商品進行預測 predict = {}

for x in not_score:

# 所有使用者對該商品的打分資訊 item = data[:, x]

# 遍歷對每一個使用者對該商品的評分【這裡包含了被推薦人,因為他的權重是0,所以不影響最終的加權權重】 for i in range(m):

if item[i, 0] != 0:

if x not in predict:

# 使用者i與該使用者相似度*使用者i對該商品的評分predict[x] = w[user, i] * item[i, 0]

else: predict[x] = predict[x] + w[user, i] * item[i, 0]

# 按照預測值大小排序 return sorted(predict.items(), key=lambda p: p[1], reverse=True)

# 基於商品的協同過濾推薦演算法具體實現,如下:

def item_based_recommend(data, w, user): """ :param data(mat): 使用者商品矩陣 :param w(mat): 使用者相似度矩陣 :param user(int): 使用者編號 :return: predict(list): 推薦列表 """ # 講使用者商品矩陣轉置成商品使用者矩陣 # data = data.T m, n = np.shape(data) # m為商品數量, n為使用者數量 # 用user的商品資訊 user_product = data[:, user].T

# 找到使用者user沒有打分的商品[在他未購買的裡面選出推薦項] not_score = []

# 變數該使用者對應的商品,找到沒有評分的 for i in range(m):

if user_product[0, i] == 0: not_score.append(i)

# 對沒有打分的商品進行預測 predict = {}

for x in not_score:

# 該user對該商品的打分資訊 item = user_product

# 遍歷所有g商品 for i in range(m):

# 該使用者買過這個商品 if item[0, i] != 0:

if x not in predict:

# 推薦權值 = 該商品與這個商品之間相似度*該使用者過的商品的評分

predict[x] = w[x, i] * item[0, i]

else: predict[x] = predict[x] + w[x, i] * item[0, i]

# 按照預測值大小排序 return sorted(predict.items(), key=lambda p: p[1], reverse=True)

# 1、定義:我們獲取並處理後的資料的格式

# 一行,表示某使用者對各商品的評分

# 一列,代表不同使用者對同一個商品的打分情況,若給使用者沒有評價過該商品,則表示這個是未購買過

''' 商品1,商品2,商品3,商品4,商品5 使用者A [4, 3, 0, 5, 0], 使用者B [5, 0, 4, 4, 0], [4, 0, 5, 0, 3], [2, 3, 0, 1, 0], [0,4, 2, 0, 5] '''""" 一、UserCF 基於使用者的協同過濾演算法: 首先計算使用者-使用者之間的相似度 找出該使用者u沒買過的商品I==候選推薦資料集 遍歷所有使用者[所有買過I商品的使用者U]:求和{ 使用者U與使用者u的相似度 * 使用者U對商品I的評分 } <利用所有買過候選集商品的使用者評分*使用者與該使用者的相似度-->得出j候選集的得分> """

# 使用者-商品-評分矩陣
User1 = np.mat([     [4, 0, 0, 5,1,0,0],     [5, 0, 4, 4,2,1,3],     [4, 0, 5, 0,2,0,2],     [2, 3, 0, 1,3,1,1],     [0, 4, 2, 0,1,1,4], ])
# print User1
# 使用者之間相似性矩陣:計算任意使用者之間的餘弦距離
w = similarity(np.mat(User1))
print "使用者之間相似度:n",w
# 給U0使用者推薦商品:
predict = user_based_recommend(User1, w, 0)
print predict
"""

二、ItemCF 基於項的協同過濾演算法:是通過基於項的相似性來進行計算的 計算商品-商品之間的相似度 找出該使用者u沒買過的商品I==候選推薦資料集 遍歷所有商品J[該使用者u買過的商品J]==>求和{ 商品I與商品J的相似度 * 使用者u對商品J的評分 } <只利用u自己的購買過的商品,然後根據商品之間的相似度*自己對該商品的評分---得到該候選商品的得分> """

# 首先將使用者-商品矩陣,轉置成商品-使用者矩陣
data = User1.T
print "ItemCF:商品-使用者-評分:n",data
# 然後計算商品之間相似性矩陣
w = similarity(data)
print "商品之間相似度:n",w
# 給U0使用者推薦商品:
predict = item_based_recommend(data, w, 0)
print predict