一、推薦系統的主要方法
推薦系統的目的是聯系用戶的興趣和物品,這種聯系需要依賴不同的媒介。目前流行的推薦系統基本上通過以下3種方式聯系用戶興趣和物品:
(1)利用用戶喜歡過的物品,給用戶推薦與他喜歡過的物品相似的物品。
(2)利用和用戶興趣相似的其他用戶,給用戶推薦那些和他們興趣愛好相似的其它用戶喜歡的物品。
(3)通過一些特征聯系用戶和物品,給用戶推薦那些具有用戶喜歡的特征的物品。這里的特征有不同的表現方式,可以是物品的屬性集合,也可以是隱語義向量。
二、測試數據
為了便于理解,這里只很了很少的數據量。tagdata.txt中的數據為:
劉一 黃飛鴻 movie
劉一 風清揚 music
陳二 黃飛鴻 movie
陳二 黃昏 music
張三 黃飛鴻 movie
張三 新龍門客棧 movie
張三 愛就一個字 music
李四 新龍門客棧 movie
李四 愛就一個字 music
李四 古拉格群島 book
王五 愛就一個字 music
三、對應關系表
從測試數據,可以計算出:
(一)用戶-物品對應關系
用戶 | 物品 | 物品數量 |
---|---|---|
劉一 | 黃飛鴻 | 1 |
劉一 | 風清揚 | 1 |
陳二 | 黃飛鴻 | 1 |
陳二 | 黃昏 | 1 |
張三 | 黃飛鴻 | 1 |
張三 | 新龍門客棧 | 1 |
張三 | 愛就一個字 | 1 |
李四 | 新龍門客棧 | 1 |
李四 | 愛就一個字 | 1 |
李四 | 古拉格群島 | 1 |
王五 | 愛就一個字 | 1 |
(二)用戶-標簽對應關系
用戶 | 標簽 | 標簽數量 |
---|---|---|
劉一 | movie | 1 |
劉一 | music | 1 |
陳二 | movie | 1 |
陳二 | music | 1 |
張三 | movie | 2 |
張三 | music | 1 |
李四 | movie | 1 |
李四 | music | 1 |
李四 | book | 1 |
王五 | music | 1 |
(三)物品-標簽對應關系
物品 | 標簽 | 標簽數量 |
---|---|---|
黃飛鴻 | movie | 3 |
風清揚 | music | 1 |
黃昏 | music | 1 |
新龍門客棧 | movie | 2 |
愛就一個字 | music | 3 |
古拉格群島 | book | 1 |
(四)標簽-物品對應關系表
標簽 | 物品 | 物品數量 |
---|---|---|
movie | 黃飛鴻 | 3 |
movie | 新龍門客棧 | 2 |
music | 風清揚 | 1 |
music | 黃昏 | 1 |
music | 愛就一個字 | 3 |
book | 古拉格群島 | 1 |
四、計算推薦列表
(一)推薦列表
以用戶“劉一”為例
“劉一”打過標簽的物品有“黃飛鴻”和“風清揚”,對應的標簽為“movie”和“music”
在“標簽-物品”對應關系表中,
moive標簽對應的物品有“黃飛鴻”和“新龍門客?!?。因為物品“黃飛鴻”“劉一”已經打過標簽了,說明“劉一”已經看過了這部電影。不能再向“劉一”推薦這部電影。但是“劉一”沒看過“新龍門客?!保砸颉皠⒁弧蓖扑]“新龍門客?!薄?br>
music標簽對應的物品有“風清揚”、“黃昏”和“愛就一個字”?!帮L清揚”已經被“劉一”打過標簽了,說明已經聽過了,不能再推薦了。“黃昏”和“愛就一個字”沒被“劉一”打過標簽,可以推薦。
(二)排序
還可以對推薦的物品,根據物品/標簽數量進行排序。
從“物品-標簽”對應關系表或者“標簽-物品”對應關系表可以看出,給“劉一”推薦的“新龍門客棧”、“黃昏”和“愛就一個字”,其物品/標簽數量分別為2、1、3。所以排序后的推薦列表為{“愛就一個字”,“新龍門客?!?,“黃昏”}。
(三)代碼
def Recommend(user):
recommend_list = dict()
tagged_item = user_items[user]
for tag, wu in user_tags[user].items():
for item, wi in tag_items[tag].items():
if item not in tagged_item:
if item not in recommend_list:
recommend_list[item] = wu * wi
else:
recommend_list[item] += wu * wi
return sorted(recommend_list.items(), key = lambda a:a[1], reverse = True)
五、計算標簽流行度
(一)標簽流行度
標簽流行度可以用標簽出現的次數來表示。
從“用戶-標簽”對應關系表中可以計算出,各標簽的流行度分別為
movie : 4, music : 5, book : 1
排序后,標簽流行度為:
{music : 5, movie : 4, book : 1}
(二)代碼
def TagPopularity():
tagFreq = {}
for user in user_tags.keys():
for tag in user_tags[user].keys():
if tag not in tagFreq:
tagFreq[tag] = 1
else:
tagFreq[tag] += 1
return sorted(tagFreq.items(), key = lambda a:a[1], reverse = True)
六、計算余弦相似度
(一)定義和公式
物品之間的相似度可以用物品標簽向量的余弦相似度來衡量。
余弦相似度,又稱為余弦相似性,是通過計算兩個向量的夾角余弦值來評估他們的相似度。
假設向量a、b的坐標分別為(x1,y1)、(x2,y2) 。則:
設向量 A = (A1,A2,...,An),B = (B1,B2,...,Bn) 。推廣到多維:
(二)例子
以下表所示的推薦列表為例
物品 | 標簽 | 出現次數 |
---|---|---|
愛就一個字 | music | 3 |
新龍門客棧 | movie | 2 |
黃昏 | music | 1 |
例1:求“愛就一個字”和“新龍門客棧”之間的余弦相似度
分析:因為“愛就一個字”和“新龍門客?!钡臉撕灢灰粯?,所以余弦相似度為0
例2:求“愛就一個字”和“黃昏”的余弦相似度
分析:因為二者的標簽都是“music”,所以
余弦相似度 = (3 * 1 ) / sqrt( 3 ^ 2 * 1 ^ 2) = 3 / 3 = 1
(三)代碼
def CosineSim(item_tags,i,j):
ret = 0
for tag,w in item_tags[i].items(): #求物品i,j的標簽交集數目
if tag in item_tags[j]:
ret += w * item_tags[j][tag]
if ret == 0:
return 0
ni = 0
nj = 0
for tag, wi in item_tags[i].items(): #統計 i 的標簽數目
ni += wi * wi
for tag, wj in item_tags[j].items(): #統計 j 的標簽數目
nj += wj * wj
return ret/math.sqrt(ni * nj) #返回余弦值
七、計算推薦列表多樣性
(一)公式
假設R(u)為給用戶u的長度為N的推薦列表。在得到物品之間的相似度度量后,我們可以用如下公式計算一個推薦列表的多樣性:
(二)例子
以下表所示的推薦列表為例
物品 | 標簽 | 標簽數量 |
---|---|---|
愛就一個字 | music | 3 |
新龍門客棧 | movie | 2 |
黃昏 | music | 1 |
“愛就一個字”與“新龍門客?!钡挠嘞蚁嗨贫葹?,與“黃昏”的余弦相似度為1
“新龍門客?!迸c“愛就一個字”的余弦相似度為0,與“黃昏”的余弦相似度為0
“黃昏”與“愛就一個字”的余弦相似度為1,與“新龍門客?!钡挠嘞蚁嗨贫葹?
所以,Diversity = (0+1+0+0+1+0)/6 = 1/3
八、完整的程序
#-*-coding:utf-8-*-
import pdb
import math
user_items = dict()
user_tags = dict()
item_tags = dict()
tag_items = dict()
def addValueToMat(mat, key, value):
if key not in mat:
mat[key] = dict()
mat[key][value] = 1
else:
if value not in mat[key]:
mat[key][value] = 1
else:
mat[key][value] += 1
def InitStat():
data_file = open('tagdata.txt')
line = data_file.readline()
while line:
terms = line.split("\t")
user = terms[0]
item = terms[1]
tag = terms[2]
addValueToMat(user_items, user, item)
addValueToMat(user_tags, user, tag)
addValueToMat(item_tags, item, tag)
addValueToMat(tag_items, tag, item)
line = data_file.readline()
data_file.close()
# 計算推薦列表
def Recommend(user):
recommend_list = dict()
tagged_item = user_items[user]
for tag, wu in user_tags[user].items():
for item, wi in tag_items[tag].items():
if item not in tagged_item:
if item not in recommend_list:
recommend_list[item] = wu * wi
else:
recommend_list[item] += wu * wi
return sorted(recommend_list.items(), key = lambda a:a[1], reverse = True)
# 統計標簽流行度
def TagPopularity():
tagFreq = {}
for user in user_tags.keys():
for tag in user_tags[user].keys():
if tag not in tagFreq:
tagFreq[tag] = 1
else:
tagFreq[tag] += 1
return sorted(tagFreq.items(), key = lambda a:a[1], reverse = True)
#計算余弦相似度
def CosineSim(item_tags,i,j):
ret = 0
for tag,w in item_tags[i].items(): #求物品i,j的標簽交集數目
if tag in item_tags[j]:
ret += w * item_tags[j][tag]
if ret == 0:
return 0
ni = 0
nj = 0
for tag, wi in item_tags[i].items(): #統計 i 的標簽數目
ni += wi * wi
for tag, wj in item_tags[j].items(): #統計 j 的標簽數目
nj += wj * wj
return ret/math.sqrt(ni * nj) #返回余弦值
def Diversity(item_tags, recommend_items):
ret = 0
n = 0
for i in dict(recommend_items).keys():
for j in dict(recommend_items).keys():
if i == j:
continue
ret += CosineSim(item_tags, i ,j)
n += 1
return ret / n
InitStat()
recommend_list = Recommend("劉一")
print("推薦列表: %s" % recommend_list)
tagFreq = TagPopularity()
print("標簽流行度:%s" % tagFreq)
diversity = Diversity(item_tags, recommend_list)
print("列表多樣性:%s" % diversity)
運行結果:
九、Github源碼下載
十、參考資料
http://blog.csdn.net/gamer_gyt/article/details/51684716
了解小朋友學編程請加QQ307591841(微信與QQ同號),或QQ群581357582。
關注公眾號請掃描二維碼
qrcode_for_kidscode_258.jpg