推薦算法
1 推薦模型建構流程
Data(資料)->Features(特征)->ML Algorithm(選擇算法訓練模型)->Prediction Output(預測輸出)
- 資料清洗/資料處理
- 資料來源
- 顯性資料
- Rating 打分
- Comments 評論/評價
- 隐形資料
- Order history 曆史訂單
- Cart events 加購物車
- Page views 頁面浏覽
- Click-thru 點選
- Search log 搜尋記錄
- 顯性資料
- 資料量/資料能否滿足要求
- 資料來源
- 特征工程
- 從資料中篩選特征
- 一個給定的商品,可能被擁有類似品味或需求的使用者購買
- 使用使用者行為資料描述商品
- 從資料中篩選特征
- 用資料表示特征
- 将所有使用者行為合并在一起 ,形成一個user-item 矩陣
- 選擇合适的算法
- 協同過濾
- 基于内容
- 産生推薦結果
- 對推薦結果進行評估(評估方法後面章節介紹),評估通過後上線
2 最經典的推薦算法:協同過濾推薦算法(Collaborative Filtering)
算法思想:物以類聚,人以群分
基本的協同過濾推薦算法基于以下假設:
- “跟你喜好相似的人喜歡的東西你也很有可能喜歡” :基于使用者的協同過濾推薦(User-based CF)
- “跟你喜歡的東西相似的東西你也很有可能喜歡 ”:基于物品的協同過濾推薦(Item-based CF)
實作協同過濾推薦有以下幾個步驟:
-
找出最相似的人或物品:TOP-N相似的人或物品
通過計算兩兩的相似度來進行排序,即可找出TOP-N相似的人或物品
-
根據相似的人或物品産生推薦結果
利用TOP-N結果生成初始推薦結果,然後過濾掉使用者已經有過記錄的物品或明确表示不感興趣的物品
以下是一個簡單的示例,資料集相當于一個使用者對物品的購買記錄表:打勾表示使用者對物品的有購買記錄
-
關于相似度計算這裡先用一個簡單的思想:如有兩個同學X和Y,X同學愛好[足球、籃球、乒乓球],Y同學愛好[網球、足球、籃球、羽毛球],可見他們的共同愛好有2個,那麼他們的相似度可以用:2/3 * 2/4 = 1/3 ≈ 0.33 來表示。
User-Based CF
Item-Based CF
3 相似度計算(Similarity Calculation)
相似度的計算方法
歐氏距離, 是一個歐式空間下度量距離的方法. 兩個物體, 都在同一個空間下表示為兩個點, 假如叫做p,q, 分别都是n個坐标, 那麼歐式距離就是衡量這兩個點之間的距離. 歐氏距離不适用于布爾向量之間
歐氏距離的值是一個非負數, 最大值正無窮, 通常計算相似度的結果希望是[-1,1]或[0,1]之間,一般可以使用
如下轉化公式:
餘弦相似度
度量的是兩個向量之間的夾角, 用夾角的餘弦值來度量相似的情況
兩個向量的夾角為0是,餘弦值為1, 當夾角為90度是餘弦值為0,為180度是餘弦值為-1
餘弦相似度在度量文本相似度, 使用者相似度 物品相似度的時候較為常用
餘弦相似度的特點, 與向量長度無關,餘弦相似度計算要對向量長度歸一化, 兩個向量隻要方向一緻,無論程度強弱, 都可以視為'相似'
皮爾遜相關系數Pearson
實際上也是餘弦相似度, 不過先對向量做了中心化, 向量a b各自減去向量的均值後, 再計算餘弦相似度
皮爾遜相似度計算結果在-1,1之間 -1表示負相關, 1表示正相關
度量兩個變量是不是同增同減
皮爾遜相關系數度量的是兩個變量的變化趨勢是否一緻, 不适合計算布爾值向量之間的相關度
傑卡德相似度 Jaccard
兩個集合的交集元素個數在并集中所占的比例, 非常适用于布爾向量表示
分子是交集格式、分母是并集個數
如何選擇相似度計算方法
餘弦相似度/皮爾遜相關系數适合使用者評分資料(實數值),
傑卡德相似度适用于隐式回報資料(0,1布爾值 是否收藏,是否點選,是否加購物車)
4 協同過濾推薦算法代碼實作:
- 建構資料集:
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 建構資料集
datasets = [
["buy",None,"buy","buy",None],
["buy",None,None,"buy","buy"],
["buy",None,"buy",None,None],
[None,"buy",None,"buy","buy"],
["buy","buy","buy",None,"buy"],
]
- 計算時我們資料通常都需要對資料進行處理,或者編碼,目的是為了便于我們對資料進行運算處理,比如這裡是比較簡單的情形,我們用1、0分别來表示使用者的是否購買過該物品,則我們的資料集其實應該是這樣的:
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 使用者購買記錄資料集
datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]
import pandas as pd
df = pd.DataFrame(datasets,
columns=items,
index=users)
print(df)
- 有了資料集,接下來我們就可以進行相似度的計算,不過對于相似度的計算其實是有很多專門的相似度計算方法的,比如餘弦相似度、皮爾遜相關系數、傑卡德相似度等等。這裡我們選擇使用傑卡德相似系數[0,1]
from sklearn.metrics import jaccard_similarity_score
# 直接計算某兩項的傑卡德相似系數
# 計算Item A 和Item B的相似度
print(jaccard_similarity_score(df["Item A"], df["Item B"]))
# 計算所有的資料兩兩的傑卡德相似系數
from sklearn.metrics.pairwise import pairwise_distances
# 計算使用者間相似度
user_similar = 1 - pairwise_distances(df, metric="jaccard")
user_similar = pd.DataFrame(user_similar, columns=users, index=users)
print("使用者之間的兩兩相似度:")
print(user_similar)
# 計算物品間相似度
item_similar = 1 - pairwise_distances(df.T, metric="jaccard")
item_similar = pd.DataFrame(item_similar, columns=items, index=items)
print("物品之間的兩兩相似度:")
print(item_similar)
- 有了兩兩的相似度,接下來就可以篩選TOP-N相似結果,并進行推薦了
- User-Based CF
import pandas as pd
import numpy as np
from pprint import pprint
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 使用者購買記錄資料集
datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]
df = pd.DataFrame(datasets,
columns=items,
index=users)
# 計算所有的資料兩兩的傑卡德相似系數
from sklearn.metrics.pairwise import pairwise_distances
# 計算使用者間相似度 1-傑卡德距離=傑卡德相似度
user_similar = 1 - pairwise_distances(df, metric="jaccard")
user_similar = pd.DataFrame(user_similar, columns=users, index=users)
print("使用者之間的兩兩相似度:")
print(user_similar)
topN_users = {}
# 周遊每一行資料
for i in user_similar.index:
# 取出每一列資料,并删除自身,然後排序資料
_df = user_similar.loc[i].drop([i])
#sort_values 排序 按照相似度降序排列
_df_sorted = _df.sort_values(ascending=False)
# 從排序之後的結果中切片 取出前兩條(相似度最高的兩個)
top2 = list(_df_sorted.index[:2])
topN_users[i] = top2
print("Top2相似使用者:")
pprint(topN_users)
# 準備空白dict用來儲存推薦結果
rs_results = {}
#周遊所有的最相似使用者
for user, sim_users in topN_users.items():
rs_result = set() # 存儲推薦結果
for sim_user in sim_users:
# 建構初始的推薦結果
rs_result = rs_result.union(set(df.loc[sim_user].replace(0,np.nan).dropna().index))
# 過濾掉已經購買過的物品
rs_result -= set(df.loc[user].replace(0,np.nan).dropna().index)
rs_results[user] = rs_result
print("最終推薦結果:")
pprint(rs_results)
- Item-Based CF
import pandas as pd
import numpy as np
from pprint import pprint
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 使用者購買記錄資料集
datasets = [
[1,0,1,1,0],
[1,0,0,1,1],
[1,0,1,0,0],
[0,1,0,1,1],
[1,1,1,0,1],
]
df = pd.DataFrame(datasets,
columns=items,
index=users)
# 計算所有的資料兩兩的傑卡德相似系數
from sklearn.metrics.pairwise import pairwise_distances
# 計算物品間相似度
item_similar = 1 - pairwise_distances(df.T, metric="jaccard")
item_similar = pd.DataFrame(item_similar, columns=items, index=items)
print("物品之間的兩兩相似度:")
print(item_similar)
topN_items = {}
# 周遊每一行資料
for i in item_similar.index:
# 取出每一列資料,并删除自身,然後排序資料
_df = item_similar.loc[i].drop([i])
_df_sorted = _df.sort_values(ascending=False)
top2 = list(_df_sorted.index[:2])
topN_items[i] = top2
print("Top2相似物品:")
pprint(topN_items)
rs_results = {}
# 建構推薦結果
for user in df.index: # 周遊所有使用者
rs_result = set()
for item in df.ix[user].replace(0,np.nan).dropna().index: # 取出每個使用者目前已購物品清單
# 根據每個物品找出最相似的TOP-N物品,建構初始推薦結果
rs_result = rs_result.union(topN_items[item])
# 過濾掉使用者已購的物品
rs_result -= set(df.loc[user].replace(0,np.nan).dropna().index)
# 添加到結果中
rs_results[user] = rs_result
print("最終推薦結果:")
pprint(rs_results)
關于協同過濾推薦算法使用的資料集
在前面的demo中,我們隻是使用使用者對物品的一個購買記錄,類似也可以是比如浏覽點選記錄、收聽記錄等等。這樣資料我們預測的結果其實相當于是在預測使用者是否對某物品感興趣,對于喜好程度不能很好的預測。
是以在協同過濾推薦算法中其實會更多的利用使用者對物品的“評分”資料來進行預測,通過評分資料集,我們可以預測使用者對于他沒有評分過的物品的評分。其實作原理和思想和都是一樣的,隻是使用的資料集是使用者-物品的評分資料。
關于使用者-物品評分矩陣
使用者-物品的評分矩陣,根據評分矩陣的稀疏程度會有不同的解決方案
- 稠密評分矩陣
- 稀疏評分矩陣
這裡先介紹稠密評分矩陣的處理,稀疏矩陣的處理相對會複雜一些,我們到後面再來介紹。
使用協同過濾推薦算法對使用者進行評分預測
- 資料集
目的:預測使用者1對物品E的評分
- 建構資料集:注意這裡建構評分資料時,對于缺失的部分我們需要保留為None,如果設定為0那麼會被當作評分值為0去對待
users = ["User1", "User2", "User3", "User4", "User5"]
items = ["Item A", "Item B", "Item C", "Item D", "Item E"]
# 使用者購買記錄資料集
datasets = [
[5,3,4,4,None],
[3,1,2,3,3],
[4,3,4,3,5],
[3,3,1,5,4],
[1,5,5,2,1],
]
計算相似度:對于評分資料這裡我們采用皮爾遜相關系數[-1,1]來計算,-1表示強負相關,+1表示強正相關
pandas中corr方法可直接用于計算皮爾遜相關系數
df = pd.DataFrame(datasets,
columns=items,
index=users)
print("使用者之間的兩兩相似度:")
# 直接計算皮爾遜相關系數
# 預設是按列進行計算,是以如果計算使用者間的相似度,目前需要進行轉置
user_similar = df.T.corr()
print(user_similar.round(4))
print("物品之間的兩兩相似度:")
item_similar = df.corr()
print(item_similar.round(4))
-
可以看到與使用者1最相似的是使用者2和使用者3;與物品A最相似的物品分别是物品E和物品D。
注意:我們在預測評分時,往往是通過與其有正相關的使用者或物品進行預測,如果不存在正相關的情況,那麼将無法做出預測。這一點尤其是在稀疏評分矩陣中尤為常見,因為稀疏評分矩陣中很難得出正相關系數。
-
評分預測:
User-Based CF 評分預測:使用使用者間的相似度進行預測
關于評分預測的方法也有比較多的方案,下面介紹一種效果比較好的方案,該方案考慮了使用者本身的評分評分以及近鄰使用者的權重平均相似度打分來進行預測:
我們要預測使用者1對物品E的評分,那麼可以根據與使用者1最近鄰的使用者2和使用者3進行預測,計算如下:
最終預測出使用者1對物品5的評分為3.91
Item-Based CF 評分預測:使用物品間的相似度進行預測
這裡利用物品相似度預測的計算同上,同樣考慮了使用者自身的平均打分因素,結合預測物品與相似物品的權重平均相似度打分進行來進行預測
我們要預測使用者1對物品E的評分,那麼可以根據與物品E最近鄰的物品A和物品D進行預測,計算如下:
對比可見,User-Based CF預測評分和Item-Based CF的評分結果也是存在差異的,因為嚴格意義上他們其實應當屬于兩種不同的推薦算法,各自在不同的領域不同場景下,都會比另一種的效果更佳,但具體哪一種更佳,必須經過合理的效果評估,是以在實作推薦系統時這兩種算法往往都是需要去實作的,然後對産生的推薦效果進行評估分析選出更優方案。