基於耦合網絡的推薦系統

基於耦合網絡的推薦系統

做者:陳東瑞 前端

1.複雜網絡基礎知識

當咱們拿起手機給家人、朋友或者同事撥打電話時,就不知不覺中參與到了社交網絡造成的過程當中;當咱們登上高鐵或者飛機時,就能夠享受交通網絡給咱們帶來的方便;即便當咱們躺在牀上什麼也不幹時,大腦中的神經元們也會造成巨大的複雜網絡相互傳遞信號,幫助咱們思考或者行動。複雜網絡是將現實世界中各類大型複雜系統抽象成網絡來進行研究的一種理論工具,在天然界中存在的大量複雜系統均可以經過形形色色的網絡加以描述。
python

image.png

1.1 網絡的表示方法

一個典型的網絡是由許多節點與節點之間的連邊組成,其中節點用來表明真實系統中不一樣的個體,而邊則用來表示節點之間的關係,每每是兩個節點之間存在某種特定的關係則連一條邊,反之則無鏈接,邊相連的兩個節點在網絡中被看做是相鄰的。爲了方便計算,咱們一般使用鄰接矩陣來表示網絡。根據網絡的邊的類型不一樣,能夠將網絡分爲無權無向網絡、有向網絡、含權網絡,對應的鄰接矩陣表示以下:
網絡

image.png

1.2 網絡的統計特徵

  • app

    :與節點直接相連的邊數;在有向網絡中能夠分爲出度和入度。dom

  • 彙集係數:節點的鄰居間互爲鄰居的可能,衡量的是網絡的集團化程度svg

<br />咱們對所計算出的彙集係數求算術平均數,能夠獲得平均彙集係數,並以此來衡量整個網絡的彙集程度。
複製代碼
  • 最短路徑:兩個節點相連的最短連通路徑
  • 介數:介數包括節點介數和邊介數。
    • 節點介數指網絡中全部最短路徑中通過該節點的數量比例
    • 邊介數則指網絡中全部最短路徑中通過該邊的數量比例
    • 介數反映了相應的節點或者邊在整個網絡中的做用和影響力

1.3 常見的複雜網絡模型

經常使用的網絡模型分爲規則網絡、隨機網絡、小世界網絡、無標度網絡四類。工具

  • 規則網絡

規則網絡是最簡單的網絡模型。在這種類型的網絡中,任意兩個節點之間的鏈接遵循既定的規則,一般每一個節點的近鄰數目都相同。測試

  • 隨機網絡

節點之間是否產生連邊是徹底隨機的。大數據

  • 小世界網絡

小世界網絡模型是由瓦茨和斯特羅加茨在1998年《天然》上發表的《小世界網絡的集體動力學》一文中提出的。他們發現,規則網絡的羣聚性較高,但網絡之平均距離也大;而隨機網絡的平均距離較短,其羣聚性也低。真實世界的網絡既非徹底規則,也非徹底隨機,而是介於這二者之間,因而有學者引入了小世界網絡模型。網站

  • 無標度網絡

無標度網絡是在網絡中的大部分節點(小度節點)只和不多節點鏈接,而有極少的節點與(大度節點)很是多的節點鏈接。

image.png
image.png
image.png
image.png

2. 基於複雜網絡實現推薦系統的背景介紹

鏈路預測是指如何經過已知的網絡結構等信息,預測網絡中還沒有產生連邊的兩個節點之間產生鏈接的可能性。預測那些已經存在但還沒有被發現的鏈接其實是一種數據挖掘的過程,而對於將來可能產生的連邊的預測則與網絡的演化相關。鏈路預測能夠應用在電商網站中。若是將電商網站中的商品當作一類節點,用戶當作另外一類節點,若是用戶A購買了商品b,A與b之間則造成一條連邊,這種邊只在不一樣類型的節點間存在的網絡成爲二分網絡,而在二分網絡中的鏈路預測問題其實也是推薦系統的一種。

image.png

下面咱們來簡單介紹一個基於複雜網絡的作推薦系統的文章《Information Filtering via Biased Random Walk on Coupled Social Network》。文章經過將用戶的社交網絡和用戶——商品二分圖網絡進行耦合,綜合了用戶的社交信息與商品偏好信息對用戶進行商品推薦。
耦合社交網絡(CSN)包含耦合節點(用戶),其在社交網絡層中造成領導者——跟隨者關係和信息網絡層中的收藏關係。下圖是一個簡單的耦合社交網絡示意圖,圓圈表示用戶,方塊表示對象。上半部分是五個用戶的社交關係網絡,
指向
的連邊表示,
的追隨者,他倆之間存在必定程度的類似性。下半部分是一個二分網絡,對象
與用戶
之間存在連邊,表示用戶
收藏了
 。若只有下半部分網絡,咱們沒法將商品
推薦給用戶
,當咱們將社交網絡中
之間的類似性考慮進來後,咱們能夠將對象
推薦給用戶
。接下來,咱們來具體解釋該方法如何在推薦系統中發揮做用。
 
image.png

3. 模型介紹

對一個推薦系統,咱們將其分紅兩個部分,用戶集

和對象集 
,表示有
個用戶和
個對象。定義鄰接矩陣
來表示該網絡,

鄰接矩陣
來表示用戶——對象二分圖,

3.1 社交網絡上的隨機遊走


  • 是社交網絡上的轉移機率,從用戶
    遊走到用戶

  • 表示在t時刻其餘用戶遊走到用戶
    的機率,

  • 初始機率
    • 對於目標用戶
    • 對於其餘用戶
#社交網絡上的遊走
#輸入用戶ID,機率prob,文中lama,遊走步長step
user_id = '23298'
prob = 1
step = 3
# def social_network_walk(user_id, prob, step):
user_group = trust_df.groupby(trust_df[0])

#第一步遊走
id_neighbors = list(user_group.get_group(user_id)[1].values)
user_prob_dic = {}
for user_id in id_neighbors:
        user_prob_dic[user_id] = prob/len(id_neighbors)
user_dict =  user_prob_dic.copy()
#以後的遊走
for _ in range(step-2):
    for item in user_dict.items():
        uesr_id = item[0]
        prob = item[1]
        id_neighbors = list(user_group.get_group(user_id)[1].values)
        for user_id in id_neighbors:
            try:
                user_prob_dic[user_id] += prob/len(id_neighbors)
            except KeyError:
                user_prob_dic[user_id] = prob/len(id_neighbors)
    user_dict =  user_prob_dic.copy()
# return user_dict
user_dict
複製代碼

3.2 二分圖上的隨機遊走

  • 用戶到商品的轉移機率:
  • 商品到用戶的轉移機率:
  • 定義 
     和 
     爲二部圖中商品 
     和用戶 
     在時刻的機率



爲奇數且 
 時,
 表示用戶 
 (初始值設爲1的用戶)選擇未收藏商品
的機率。

#在二部圖網絡上的遊走
#第一步遊走,從用戶到商品
# def bipartite_walk(user_id, perct):
user_id = '23298'
prob = 1
objection_group = ratings_df.groupby(ratings_df[0])  #以用戶未依據,對對象進行分類,同一個用戶收藏的對象
user_group = ratings_df.groupby(ratings_df[1])    #以對象爲依據,對用戶進行分類,以對象爲依據,同一對象被哪些用戶收藏
objection_dict = {}
user_dict = {}

#第一步用戶到對象
user_neighbors = objection_group.get_group(user_id)[1].values  #用戶的鄰居是對象
for objection_id in user_neighbors:
    print(objection_id)
    objection_dict[objection_id] = prob/len(user_neighbors)
    
# #第二步對象到用戶
# objection_lis = objection_dict.keys()
for item in objection_dict.items():
    objection_id = item[0]
    prob = item[1]
    objection_neighbors = user_group.get_group(objection_id)[0].values
    for user_id in objection_neighbors:
        try:
            user_dict[user_id] += prob/len(objection_neighbors)
        except KeyError:
            user_dict[user_id] = prob/len(objection_neighbors)
# # 
# #第三步,用戶到對象
for item in user_dict.items():
    user_id = item[0]
    prob = item[1]
    user_neighbor = list(objection_group.get_group(user_id)[1].values)
    for obj_id in user_neighbor:
        try:
            objection_dict[obj_id] += prob/len(user_neighbor)
        except KeyError:
            objection_dict[obj_id] = prob/len(user_neighbor)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
objection_dict
複製代碼

3.3 耦合社交網絡上的有偏隨機遊走

耦合網絡中,從社交網絡中用戶與二分圖網絡中商品遊走到二分圖網絡中的用戶

image.svg


初始機率:

  • 對於目標用戶
  • 對於其餘用戶
    和商品

當 

 爲奇數,且 
 時,
表示用戶 
 選擇未收藏商品 
 的機率(設定目標用戶的初始值爲1單位資源,
 時,資源從目標用戶遊走到與目標用戶相鄰對象;
 時,資源從對象再次遊走到用戶)。

#耦合網絡遊走,用戶23298在耦合網絡隨機遊走,步長爲三,轉移機率0.7
user_id = '23298'
prob_social = 0.7
step = 3
prob_bi = 1-prob_social
social_user_group = trust_df.groupby(trust_df[0])
#以用戶未依據,對對象進行分類,同一個用戶收藏的對象
bi_objection_group = ratings_df.groupby(ratings_df[0])  
#以對象爲依據,對用戶進行分類,以對象爲依據,同一對象被哪些用戶收藏
bi_user_group = ratings_df.groupby(ratings_df[1])   
objection_dict = {}
user_dict = {}

#第一步用戶到對象
user_neighbors = bi_objection_group.get_group(user_id)[1].values  #用戶的鄰居是對象
for objection_id in user_neighbors:
    objection_dict[objection_id] = prob_social/len(user_neighbors)

for _ in range(int((step-1)/2)) :   
    #第二步,對象到用戶 
    for item in objection_dict.items():
        objection_id = item[0]
        prob = item[1]
        objection_neighbors = bi_user_group.get_group(objection_id)[0].values
        for user_id in objection_neighbors:
            try:
                user_dict[user_id] += prob/len(objection_neighbors)
            except KeyError:
                user_dict[user_id] = prob/len(objection_neighbors)


    user_neighbors = list(social_user_group.get_group(user_id)[1].values)
    for user_id in user_neighbors:
        try:
            user_dict[user_id] += prob_social/len(user_neighbors)
        except KeyError:
            user_dict[user_id] = prob_social/len(user_neighbors)


    # #第三步,用戶到對象
    for item in user_dict.items():
        user_id = item[0]
        prob = item[1]
        user_neighbor = list(objection_group.get_group(user_id)[1].values)
        for obj_id in user_neighbor:
            try:
                objection_dict[obj_id] += prob/len(user_neighbor)
            except KeyError:
                objection_dict[obj_id] = prob/len(user_neighbor)  
objection_dict
複製代碼

評價指標:

  •  精確度,用戶選擇的商品在推薦列表中的比例。

:對用戶 
 推薦的商品出如今測試集中的數量,
:推薦列表的長度。

  •  召回率,推薦的商品在用戶收藏列表中的比例。

:用戶 
 在測試集中收藏的商品數量

  •  漢明距離,衡量用戶推薦列表的多樣性。
     是用戶 
     與用戶 
     的推薦列表中具備相同商品的數量。
  • :衡量用戶對推薦列表的滿意度,
     是用戶未收藏的商品 
     在用戶 
     推薦列表中的位置。
     是推薦列表的長度。

4. 結果分析

4.1 數據描述

Epinions與Friendfeed兩個公開數據集均包含一個社交關係數據集和一個評分數據集。下表對數據集對應的網絡進行描述。以Epinions爲例,文章中隨機抽取一部分數據進行分析,採樣數據規模爲:4066個用戶,7649個對象,用戶與對象連邊(收藏)數量爲154122條,社交網絡連邊數爲217017。網絡密度爲5x10-3 。

Table 1: Properties of the tested data sets

11.jpg

4.2 參數
image.png
與 t 對實驗結果的影響

爲資源在社交網絡與二分圖網絡中的分配比例,
 爲遊走步長,下圖使用排序的分進行衡量,值顏色越偏冷色表示效果越好,圖中能夠看出在 
 時,預測效果較好。 當 
 時,預測效果僅依賴於二分圖網絡,隨着 
 增長,社交網絡的信息被逐漸考慮進來。

Figure1:Ranking score values on Epinions and Friendfeed data sets (color online).

Properties-of-the-tested-data-sets.jpg

        (a)Epinions                                                               (b)Friendfeed

4.3 預測效果

下表展現了預測長度 

 時,該模型與 MD(mass diffusion) 模型和 UCF(user-based CF) 模型的效果比較。

Table2 Algorithmic performance for Epinions data set with recommendation list L =20
Algorithmic-performance-for-Epinions-data-set-with-recommendation-list-i-i-20 (1).png

Table3 Algorithmic performance for Friendfeed data set with recommendation list L =20

Algorithmic-performance-for-Friendfeed-data-set-with-recommendation-list-i-i-20 (1).png


**本項目已在mo平臺實現,記得來fork呀:** momodel.cn/explore/5d7…

關於咱們

Mo(網址:https://momodel.cn)是一個支持 Python 的人工智能在線建模平臺,能幫助你快速開發、訓練並部署模型。


Mo 人工智能俱樂部 是由網站的研發與產品設計團隊發起、致力於下降人工智能開發與使用門檻的俱樂部。團隊具有大數據處理分析、可視化與數據建模經驗,已承擔多領域智能項目,具有從底層到前端的全線設計開發能力。主要研究方向爲大數據管理分析與人工智能技術,並以此來促進數據驅動的科學研究。

目前俱樂部每兩週在杭州舉辦線下論文分享與學術交流。但願能匯聚來自各行各業對人工智能感興趣的朋友,不斷交流共同成長,推進人工智能民主化、應用普及化。

image.png
相關文章
相關標籤/搜索