1. 程式人生 > >基於協同過濾演算法構建推薦系統

基於協同過濾演算法構建推薦系統

一 推薦系統介紹

  • 推薦系統是資訊過濾系統的一個子類,它根據使用者的偏好和行為,來向用戶呈現他(或她)可能感興趣的物品。推薦系統會嘗試去預測你對一個物品的喜好,以此向你推薦一個你很有可能會喜歡的物品。我們組設計的系統是一個購物系統,主要包括主頁,商品頁和推薦頁。
  • 完整專案效果點選此處檢視(此專案為Web應用,暫未對PC端進行介面適配,如無法開啟請用移動端瀏覽器進入139.199.59.246:8081瀏覽)
  • GitHub地址:https://github.com/KingsleyChung/Blockchain_Market
  1. 主頁
    主頁主頁向用戶展現了能夠購買的物品的圖片、價格以及庫存。點選商品圖片可以進入商品頁,點選主頁右下角的推薦圖示可以進入推薦頁。
  2. 商品頁
    商品頁商品頁能看到商品簡介、價格、瀏覽量等資訊,以及出現購買量與購買圖示。
  3. 推薦頁
    推薦頁系統根據使用者對某個商品的瀏覽次數、購買記錄以及該商品的總訪問量和銷量而對使用者進行的相關推薦。上圖是在已經購買了主頁的2種網球之後生成的,可以看到推薦系統基於我們的偏好,向我們推薦了可能會喜歡的Wilson護腕

二 協同過濾演算法介紹

  • 協同過濾的過程分為這三步:一開始,收集使用者資訊,然後以此生成矩陣來計算使用者關聯,最後作出高可信度的推薦。這種技術分為兩大類:一種是基於使用者的協同過濾,一種則是基於物品的協同過濾。我們的系統採用的是基於物品的協同過濾方法。
  • 基於物品的協同過濾演算法核心思想是:給使用者推薦那些和他們之前喜歡的物品相似的物品,值得注意的是,這裡所說的物品A和物品B具有很大的相似度是因為喜歡物品A的使用者大都也喜歡B。
    實現演算法主要分為兩步:
  1. 計算物品之間的相似度:
    我們使用如下的公式定義物品的相似度:


在這裡插入圖片描述

  • 其中, \mid N(i) \mid
    是喜歡物品 i 的使用者數, \mid N(j) \mid 是喜歡物品 j 的使用者數, \mid N(i) \bigcap N(j) \mid 是同時喜歡物品i和物品j的使用者數。
  • 這裡面有個假設,就是每個使用者的興趣都侷限在某幾個方面。如果使用者之間的興趣廣泛且不相交,那麼即使存在同時喜歡物品i和物品j的使用者數多,那也不能代表物品i和物品j的相似度大,因為很可能兩種物品所屬領域非常不同。
  1. 根據物品的相似度和使用者的歷史行為給使用者生成推薦列表:


在這裡插入圖片描述

  • 其中, p(u,i)表示使用者 u 對物品 j 的興趣, N(i)表示使用者喜歡的物品集合(u是該使用者喜歡的某一個物品), S(u,K)表示和物品 u 最相似的 K 個物品集合(i 是這個集合中的某一個物品), wuv 表示物品 u 和物品 v 的相似度,rvi 表示使用者 v 對物品 i 的興趣(這裡簡化rvi都等於1)。
  • 該公式的含義可以理解為:和使用者歷史上感興趣的物品越相似的物品,越有可能在使用者的推薦列表中獲得比較高的排名。

三 演算法實現

  1. 連線資料庫
def connectMongo(host, port, username, password, db):
  if username and password:
    mongo_url = "mongodb://%s:%[email protected]%s:%s/%s" % (username, password, host, port, db)
    connection = MongoClient(mongo_url)
  else:
    connection = MongoClient(host, port)
  return connection[db]
  1. 構建一個二維陣列,根據商品的瀏覽記錄,購買記錄,總瀏覽量等計算相關性
def getMatrix(db):
  matrix = list()
  goods = list(db.goods.find())
  goodsTitle = list(['username'])
  for good in goods:
    goodsTitle.append(str(good['_id']))

  users = list(db.users.find())
  for user in users:
    userRow = list([user['username']])
    for i in range(len(goods)):
      userRow.append(goods[i]['sale'] * 0.3 + goods[i]['view'] * 0.1)
    for key in user['goods']:
      for i in range(len(goods)):
        if str(goods[i]['_id']) == str(key):
          userRow[i + 1] = user['goods'][key]['bought'] * 3 + user['goods'][key]['view'] * 0.5 + goods[i]['sale'] * 0.3 + goods[i]['view'] * 0.1
          break
    matrix.append(userRow)
  return (goodsTitle, matrix)
  1. 將得到的矩陣傳給getRecommand函式,根據矩陣計算其他商品對於客戶的推薦分,最後將得分最高的商品進行推薦
def getRecommand(header, matrix): # 推薦演算法
  data = pd.DataFrame(matrix)
  data.columns = header
  data.set_index('username', inplace = True)
  corrMatrix = data.corr(method = 'pearson')

  recommandResult = list()
  for row in matrix:
    username = row[0]
    myRatings = data.loc[username].dropna()
    simCandidates = pd.Series()
    for i in range(0, len(myRatings.index)):
      sims = corrMatrix[myRatings.index[i]].dropna()
      sims = sims.map( lambda x: x * myRatings[i])
      simCandidates = simCandidates.append(sims)
    simCandidates.sort_values(inplace = True, ascending = False)
    simCandidates = simCandidates.groupby(simCandidates.index).sum()
    simCandidates.sort_values(inplace = True, ascending = False)
    recommands = list()
    for i in range(0, len(simCandidates.index)):
      if i < 4:
        recommands.append(simCandidates.index[i])
      elif i < 10 and i * 3 <= len(simCandidates.index):
        recommands.append(simCandidates.index[i])
    result = {}
    result['username'] = username
    result['recommands'] = recommands
    recommandResult.append(result)
  return recommandResult
  1. 將得到的資料寫入資料庫
def updateRecommandToDB(db, recommandForEachUser):
  for recommand in recommandForEachUser:
    db.users.update_one({'username': recommand['username']}, {'$set': {'recommands': recommand['recommands']}})

四 小組成員

姓名 學號 貢獻度
鍾文傑 15331429 50%
周銳 15331434 25%
朱薇薇 15331442 25%