1. 以用戶為基礎(User-based)的協同過濾
??基于用戶的協同過濾算法是通過用戶的歷史行為數據發(fā)現用戶對商品或內容的喜歡(如商品購買桦锄,收藏祷嘶,內容評論或分享)衍菱,并對這些喜好進行度量和打分撩幽。根據不同用戶對相同商品或內容的態(tài)度和偏好程度計算用戶之間的關系兜挨。在有相同喜好的用戶間進行商品推薦职抡。簡單的說就是如果A,B兩個用戶都購買了x,y,z三本圖書葬燎,并且給出了5星的好評。那么A和B就屬于同一類用戶∑拙唬可以將A看過的圖書w也推薦給用戶B窑邦。
1.1 尋找偏好相似的用戶
??我們模擬了5個用戶對兩件商品的評分,來說明如何通過用戶對不同商品的態(tài)度和偏好尋找相似的用戶壕探。在示例中冈钦,5個用戶分別對兩件商品進行了評分。這里的分值可能表示真實的購買李请,也可以是用戶對商品不同行為的量化指標瞧筛。例如,瀏覽商品的次數导盅,向朋友推薦商品较幌,收藏,分享白翻,或評論等等乍炉。這些行為都可以表示用戶對商品的態(tài)度和偏好程度。
??從表格中很難直觀發(fā)現5個用戶間的聯系滤馍,我們將5個用戶對兩件商品的評分用散點圖表示出來后岛琼,用戶間的關系就很容易發(fā)現了。在散點圖中巢株,Y軸是商品1的評分衷恭,X軸是商品2的評分,通過用戶的分布情況可以發(fā)現纯续,A,C,D三個用戶距離較近随珠。用戶A(3.3 6.5)和用戶C(3.6 6.3),用戶D(3.4 5.8)對兩件商品的評分較為接近猬错。而用戶E和用戶B則形成了另一個群體窗看。
??散點圖雖然直觀,但無法投入實際的應用倦炒,也不能準確的度量用戶間的關系显沈。因此我們需要通過數字對用戶的關系進行準確的度量,并依據這些關系完成商品的推薦逢唤。
1.2 相似度計算
1.2.1 歐幾里德距離評價
??歐幾里德距離評價是一個較為簡單的用戶關系評價方法拉讯。原理是通過計算兩個用戶在散點圖中的距離來判斷不同的用戶是否有相同的偏好。以下是歐幾里德距離評價的計算公式鳖藕。
??通過公式我們獲得了5個用戶相互間的歐幾里德系數魔慷,也就是用戶間的距離。系數越小表示兩個用戶間的距離越近著恩,偏好也越是接近院尔。為了相似性與數值呈正相關蜻展,我們對求得的系數取倒數,使用戶間的距離約接近邀摆,數值越大纵顾。在下面的表格中,可以發(fā)現栋盹,用戶A&C用戶A&D和用戶C&D距離較近施逾。同時用戶B&E的距離也較為接近。與我們前面在散點圖中看到的情況一致例获。
1.2.2 皮爾遜相關度評價
??皮爾遜相關度評價是另一種計算用戶間關系的方法汉额。他比歐幾里德距離評價的計算要復雜一些,但對于評分數據不規(guī)范時皮爾遜相關度評價能夠給出更好的結果躏敢。以下是一個多用戶對多個商品進行評分的示例。這個示例比之前的兩個商品的情況要復雜一些整葡,但也更接近真實的情況件余。我們通過皮爾遜相關度評價對用戶進行分組,并推薦商品遭居。
??通過計算5個用戶對5件商品的評分我們獲得了用戶間的相似度數據啼器。這里可以看到用戶A&B,C&D俱萍,C&E和D&E之間相似度較高端壳。下一步,我們可以依照相似度對用戶進行商品推薦枪蘑。
1.3 為用戶推薦商品
??當我們需要對用戶C推薦商品時损谦,首先我們檢查之前的相似度列表,發(fā)現用戶C和用戶D和E的相似度較高岳颇。換句話說這三個用戶是一個群體照捡,擁有相同的偏好。因此话侧,我們可以對用戶C推薦D和E的商品栗精。但這里有一個問題。我們不能直接推薦前面商品1-商品5的商品瞻鹏。因為這這些商品用戶C以及瀏覽或者購買過了悲立。不能重復推薦。因此我們要推薦用戶C還沒有瀏覽或購買過的商品新博。
1.4 算法優(yōu)缺點
1.4.1 算法缺點
??1. 數據稀疏性薪夕。一個大型的電子商務推薦系統(tǒng)一般有非常多的物品,用戶可能買的其中不到1%的物品赫悄,不同用戶之間買的物品重疊性較低寥殖,導致算法無法找到一個用戶的鄰居玩讳,即偏好相似的用戶。
??2. 算法擴展性嚼贡。最近鄰居算法的計算量隨著用戶和物品數量的增加而增加熏纯,不適合數據量大的情況使用。
1.5 python實現基于user的協同過濾算法:
import numpy as np
from math import sqrt
class Recommender:
# data: 數據集粤策,這里指users_rating
# k: 表示得出最相近的k的近鄰
# sim_func: 表示使用計算相似度
# n: 表示推薦的item的個數
def __init__(self, data, k = 3, sim_func='pearson', n=12):
# 數據初始化
self.k = k
self.n = n
self.sim_func = sim_func
if self.sim_func == 'pearson':
self.fn = self.pearson_sim
if type(data).__name__ == 'dict':
self.data = data
#pearson相似度
def pearson_sim(self, rating1, rating2):
sum_x = 0
sum_y = 0
sum_xy = 0
sum_x2 = 0
sum_y2 = 0
n = 0
for key in rating1:
if key in rating2:
n += 1
x = rating1[key]
y = rating2[key]
sum_x += x
sum_y += y
sum_xy += x * y
sum_x2 += pow(x, 2)
sum_y2 += pow(y, 2)
if n == 0:
return 0
dinominator = sqrt(n * sum_x2 - pow(sum_x, 2)) * sqrt(n * sum_y2 - pow(sum_y, 2))
if dinominator == 0:
return 0
else:
return (n * sum_xy - sum_x * sum_y) / dinominator
#對用戶相似度排序
def user_sim_sort(self, user_id):
distances = []
for instance in self.data:
if instance != user_id:
dis = self.fn(self.data[user_id], self.data[instance])
distances.append((instance, dis))
distances.sort(key=lambda items: items[1], reverse=True)
return distances
# recommand主體函數
def recommand(self, user_id):
# 定義一個字典樟澜,用來存儲推薦的電影和分數
recommendations = {}
# 計算出user與其它所有用戶的相似度,返回一個list
user_sim = self.user_sim_sort(user_id)
# 計算最近的k個近鄰的總距離
total_dis = 0.0
for i in range(self.k):
total_dis += user_sim[i][1]
if total_dis == 0.0:
total_dis = 1.0
# 將與user最相近的k個人中user沒有看過的書推薦給user叮盘,并且這里又做了一個分數的計算排名
for i in range(self.k):
# 第i個人的id
neighbor_id = user_sim[i][0]
# 第i個人與user的相似度轉換到[0, 1]之間
weight = user_sim[i][1] / total_dis
# 第i個用戶看過的書和相應的打分
neighbor_ratings = self.data[neighbor_id]
user_rating = self.data[user_id]
for item_id in neighbor_ratings:
if item_id not in user_rating:
if item_id not in recommendations:
recommendations[item_id] = neighbor_ratings[item_id] * weight
else:
recommendations[item_id] = recommendations[item_id] + neighbor_ratings[item_id] * weight
recommendations = list(recommendations.items())
# 做了一個排序
recommendations.sort(key=lambda items: items[1], reverse=True)
return recommendations[:self.n], user_sim
if __name__ == "__main__":
# 獲取數據
users_rating = dict()
data_path = "./ratings.csv"
with open(data_path, 'r') as file:
for line in file:
items = line.strip().split(',')
if items[0] not in users_rating:
users_rating[items[0]] = dict()
users_rating[items[0]][items[1]] = dict()
users_rating[items[0]][items[1]] = float(items[2])
user_id = '1'
recomm = Recommender(users_rating)
recommendations, user_sim = recomm.recommand(user_id)
print("movie id list:", recommendations)
print("near list:", user_sim[:15])
數據集鏈接:https://pan.baidu.com/s/14VwSvGHsNTqHeeuyG5Og1Q 密碼:1e97
2 基于物品的協同過濾算法(item-based collaborative filtering)
??基于物品的協同過濾算法與基于用戶的協同過濾算法很像秩贰,將商品和用戶互換。通過計算不同用戶對不同物品的評分獲得物品間的關系柔吼《痉眩基于物品間的關系對用戶進行相似物品的推薦。這里的評分代表用戶對商品的態(tài)度和偏好愈魏。簡單來說就是如果用戶A同時購買了商品1和商品2觅玻,那么說明商品1和商品2的相關度較高。當用戶B也購買了商品1時培漏,可以推斷他也有購買商品2的需求溪厘。
2.1 尋找相似的物品
??表格中是兩個用戶對5件商品的評分。在這個表格中我們用戶和商品的位置進行了互換牌柄,通過兩個用戶的評分來獲得5件商品之間的相似度情況畸悬。單從表格中我們依然很難發(fā)現其中的聯系,因此我們選擇通過散點圖進行展示珊佣。
??在散點圖中蹋宦,X軸和Y軸分別是兩個用戶的評分。5件商品按照所獲的評分值分布在散點圖中咒锻。我們可以發(fā)現妆档,商品1,3,4在用戶A和B中有著近似的評分,說明這三件商品的相關度較高虫碉。而商品5和2則在另一個群體中贾惦。
2.2 相似度評價
2.2.1 歐幾里德距離評價
??在基于物品的協同過濾算法中,我們依然可以使用歐幾里德距離評價來計算不同商品間的距離和關系敦捧。以下是計算公式须板。
??通過歐幾里德系數可以發(fā)現,商品間的距離和關系與前面散點圖中的表現一致兢卵,商品1,3,4距離較近關系密切习瑰。商品2和商品5距離較近。
2.2.2 皮爾遜相關度評價
??我們選擇使用皮爾遜相關度評價來計算多用戶與多商品的關系計算秽荤。下面是5個用戶對5件商品的評分表甜奄。我們通過這些評分計算出商品間的相關度柠横。
??通過計算可以發(fā)現,商品1&2课兄,商品3&4牍氛,商品3&5和商品4&5相似度較高。下一步我們可以依據這些商品間的相關度對用戶進行商品推薦烟阐。
2.3 為用戶提供基于相似物品的推薦
??這里我們遇到了和基于用戶進行商品推薦相同的問題搬俊,當需要對用戶C基于商品3推薦商品時,需要一張新的商品與已有商品間的相似度列表蜒茄。在前面的相似度計算中唉擂,商品3與商品4和商品5相似度較高,因此我們計算并獲得了商品4,5與其他商品的相似度列表檀葛。
??以下是通過計算獲得的新商品與已有商品間的相似度數據玩祟。
??加權排序推薦,這里是用戶C已經購買過的商品4,5與新商品A,B,C直接的相似程度。我們將用戶C對商品4,5的評分作為權重屿聋。對商品A,B,C進行加權排序空扎。用戶C評分較高并且與之相似度較高的商品被優(yōu)先推薦。
2.4 python實現基于item的協同過濾
from math import sqrt
class ItemBasedCF:
def __init__(self, train_file):
self.train_file = train_file
self.read_data()
# 讀取文件胜臊,并生成用戶-物品的評分表和測試集
def read_data(self):
self.train = dict()
for line in open(self.train_file):
user_id, item_id, score = line.strip().split(',')
self.train.setdefault(user_id, {})
self.train[user_id][item_id] = int(float(score))
# 建立物品-物品的共現矩陣
def item_sim(self):
C = dict() #物品-物品的共現矩陣
N = dict() #物品被多少個不同用戶購買
for user, items in self.train.items():
for i in items.keys():
N.setdefault(i, 0)
N[i] += 1
C.setdefault(i, {})
for j in items.keys():
if i == j :
continue
if j not in C[i].keys():
C[i].setdefault(j, 0)
C[i][j] += 1
#計算相似度矩陣
self.W = dict()
for i,related_items in C.items():
self.W.setdefault(i,{})
for j,cij in related_items.items():
# 余弦相似度
self.W[i][j] = cij / (sqrt(N[i] * N[j]))
return self.W
#給用戶user推薦勺卢,前K個相關用戶
def recommend(self,user,K=3,N=10):
rank = dict()
action_item = self.train[user] #用戶user產生過行為的item和評分
for item,score in action_item.items():
for j,wj in sorted(self.W[item].items(),key=lambda x:x[1],reverse=True)[0:K]:
if j in action_item.keys():
continue
if j not in rank.keys():
rank.setdefault(j,0)
rank[j] += score * wj
return dict(sorted(rank.items(),key=lambda x:x[1],reverse=True)[0:N])
if __name__ == "__main__":
CF = ItemBasedCF('./ratings.csv')
CF.item_sim()
recomm_dic = CF.recommend('1')
for k,v in recomm_dic.iteritems():
print(k,"\t",v)
4. 協同過濾優(yōu)缺點
4.1 優(yōu)點
??以用戶的角度來推薦的協同過濾系統(tǒng)有下列優(yōu)點:
??能夠過濾機器難以自動內容分析的信息伙判,如藝術品象对,音樂等。
??共享其他人的經驗宴抚,避免了內容分析的不完全或不精確勒魔,并且能夠基于一些復雜的,難以表述的概念(如信息質量菇曲、個人品味)進行過濾冠绢。
??有推薦新信息的能力〕3保可以發(fā)現內容上完全不相似的信息弟胀,用戶對推薦信息的內容事先是預料不到的『笆剑可以發(fā)現用戶潛在的但自己尚未發(fā)現的興趣偏好孵户。
??推薦個性化、自動化程度高岔留。能夠有效的利用其他相似用戶的反饋信息夏哭。加快個性化學習的速度。
4.2 缺點
??雖然協同過濾作為一推薦機制有其相當的應用献联,但協同過濾仍有許多的問題需要解決竖配。整體而言何址,最典型的問題有
??新用戶問題(New User Problem) 系統(tǒng)開始時推薦質量較差
??新項目問題(New Item Problem) 質量取決于歷史數據集
??稀疏性問題(Sparsity)
??系統(tǒng)延伸性問題(Scalability)。