当用户浏览某个物品时,标签系统非常希望用户能给这个物品打出高质量的标签,这样才能促进标签系统的良性循环。
为什么要给用户推荐标签?一般看来有以下好处。
1)方便用户输入标签。用户一般不愿意通过从键盘输入标签来给物品打标签。给用户推荐标签,可以提高用户打标签参与度。
2)提高标签质量。用户给物品打标签,同一个语义不同内容的词很庞大,而且会使计算相似度不太准确。而使用推荐标签时,我们可以对词表进行选择,首先保证词表不会出现太多的同义词,同时保证出现的词是一些比较热门的,有代表性的词。
如何给用户推荐标签,有以下四个方法。
1)PopularTags
给用户推荐整个系统中最热门的标签,这个算法太简单,以至于不能称为一种推荐算法。
def RecommendPopularTags(user,item,tags,N):
##tags字典:tag->用户使用tag的次数
tags=dict(sorted(tags.items(),key=lambda x:x[1],reverse=True)[0:N])
return tags.keys()
2)ItemPopularTags
给用户u推荐物品i最热门的标签
def RecommendItemPopularTags(user,item,item_tags,N):
##item_tags两层字典:item->(tag->物品item被打tag次数)
return dict(sorted(item_tags[item].items(),key=lambda x:x[1],reverse=True)[0:N]).keys()
3)UserPopularTags
给用户推荐他经常使用的标签
def RecommendUserPopularTags(user,item,user_tags,N):
##user_tags两层字典:user->(tags->用户打tag的次数)
return dict(sorted(user_tags[user].items(),key=lambda x:x[1],reverse=True)[0:N]).keys()
4)HybridPopularTags
前两种算法的融合,该方法通过一个系数将以上两种方法结果线性加权,然后生成最终的结果。
def RecommendHybridPopularTags(user,item,user_tags,item_tags,alpha,N):
ret=dict()
max_user_tag_weight=max(user_tags[user].values())
for tag,weight in user_tags[user].items():
ret[tag]=(1-alpha)*weight/max_user_tag_weight
max_item_tags_weight=max(item_tags[item].values())
for tag,weight in item_tags[item].items():
if tag not in ret:
ret[tag]=alpha*weight/max_item_tags_weight
else:
ret[tag]+=alpha*weight/max_item_tags_weight
return dict(sorted(ret.items(),key=lambda x:x[1],reverse=True)[0:N]).keys()
实现完整Python代码:数据源deilicous上200509数据,我们取前5万行数据进行实验,随机分为10份,其中一份做测试,另外9份做训练。这里我们根据上述四种算法,在训练集数据中分别计算出最热门的标签,物品i最热门的标签,用户u经常使用的标签。所以在划分训练测试集时,训练集和测试集中用户,物品,标签不能有任何重复,故在这里划分训练测试集时需要以user,item,tag作为主键划分。
#coding:utf-8
import pandas as pd
import numpy as np
import random
def genData():
data=pd.read_csv('200509',header=None,sep='\t')
data.columns=['date','user','item','tag']
data.drop('date',axis=1,inplace=True)
print 'genData successed!!!'
return data[:50000]
def user_item_tag(data):
##在将源数据以user,item,tag为主键构造数据,元组列表(列表里面每个元素是元组)
UIT=[]
for i in range(len(data)):
lst=list(data.loc[i])
user=lst[0]
item=lst[1]
tag=lst[2]
temp=(user,item,tag)
if temp not in UIT:
UIT.append(temp)
return UIT
def splitData(records,train,test):
##以9:1划分训练集测试集
for user,item,tag in records:
if random.randint(1,10)==1:
test.append([user,item,tag])
else:
train.append([user,item,tag])
print 'split succeed!'
return train,test
def Initstate(data):
##以训练集里数据分别计算出
##tags字典:tag->tag被打次数
##item_tags字典:item->(tag->物品item被打tag标签的次数)
##user——tags字典:user->(tag->用户user打tag标签的次数)
tags=dict()
item_tags=dict()
user_tags=dict()
for lst in data:
user=lst[0]
item=lst[1]
tag=lst[2]
if tag not in tags:
tags[tag]=0
tags[tag]+=1
if item not in item_tags:
item_tags[item]=dict()
if tag not in item_tags[item]:
item_tags[item][tag]=0
item_tags[item][tag]+=1
if user not in user_tags:
user_tags[user]=dict()
if tag not in user_tags[user]:
user_tags[user][tag]=0
user_tags[user][tag]+=1
return tags,item_tags,user_tags
def RecommendPopularTags(user,item,tags,N):
##tags字典:tag->用户使用tag的次数
tags=dict(sorted(tags.items(),key=lambda x:x[1],reverse=True)[0:N])
return tags.keys()
def RecommendItemPopularTags(user,item,item_tags,N):
##item_tags两层字典:item->(tag->物品item被打tag次数)
return dict(sorted(item_tags[item].items(),key=lambda x:x[1],reverse=True)[0:N]).keys()
def RecommendUserPopularTags(user,item,user_tags,N):
##user_tags两层字典:user->(tags->用户打tag的次数)
return dict(sorted(user_tags[user].items(),key=lambda x:x[1],reverse=True)[0:N]).keys()
def RecommendHybridPopularTags(user,item,user_tags,item_tags,alpha,N):
##上面两种算法的线性加权
ret=dict()
max_user_tag_weight=max(user_tags[user].values())
for tag,weight in user_tags[user].items():
ret[tag]=(1-alpha)*weight/max_user_tag_weight
max_item_tags_weight=max(item_tags[item].values())
for tag,weight in item_tags[item].items():
if tag not in ret:
ret[tag]=alpha*weight/max_item_tags_weight
else:
ret[tag]+=alpha*weight/max_item_tags_weight
return dict(sorted(ret.items(),key=lambda x:x[1],reverse=True)[0:N]).keys()
def getTU(test,user,item):
tags=[]
for lst in test:
t_user=lst[0]
t_item=lst[1]
t_tag=lst[2]
if (user==t_user) and (item==t_item):
tags.append(t_tag)
return tags
def GetRecommend(user,item,item_tags,user_tags,tags,N,state):
if state==1:
return RecommendItemPopularTags(user,item,item_tags,N)
if state==2:
return RecommendPopularTags(user,item,tags,N)
if state==3:
return RecommendUserPopularTags(user,item,user_tags,N)
if state==4:
return RecommendHybridPopularTags(user,item,user_tags,item_tags,0.8,N)
def Recall(train,test,tags,item_tags,user_tags,N,a):
'''
:param train: 训练集
:param test: 测试集
:param N: TopN推荐中N数目
:param k:
:return:返回召回率
'''
hit=0# 预测准确的数目
totla=0# 所有行为总数
for lst in train:
user=lst[0]
item=lst[1]
tu=getTU(test,user,item)
rank=GetRecommend(user,item,item_tags,user_tags,tags,N,a)
for item in rank:
if item in tu:
hit+=1
totla+=len(tu)
#print "Recall successed!",hit/(totla*1.0)
return hit/(totla*1.0)
def Precision(train,test,tags,item_tags,user_tags,N,a):
'''
:param train:
:param test:
:param N:
:param k:
:return:准确率
'''
hit=0
total=0
for lst in train:
user=lst[0]
item=lst[1]
tu = getTU(test,user,item)
rank = GetRecommend(user,item,item_tags,user_tags,tags,N,a)
for item in rank:
if item in tu:
hit += 1
total += N
#print "Precision successed!",hit / (total * 1.0)
return hit / (total * 1.0)
def Coverage(train,test,tags,item_tags,user_tags,N,a):
'''
计算覆盖率
:param train:训练集 字典user->items
:param test: 测试机 字典 user->items
:param N: topN推荐中N
:param k:
:return:覆盖率
'''
recommend_items=set()
all_items=set()
for lst in train:
user=lst[0]
item=lst[1]
all_items.add(item)
rank=GetRecommend(user,item,item_tags,user_tags,tags,N,a)
for item in rank:
recommend_items.add(item)
#print "Coverage successed!",len(recommend_items)/(len(all_items)*1.0)
return len(recommend_items)/(len(all_items)*1.0)
def evaluate(train,test,tags,item_tags,user_tags,N,state):
##计算一系列评测标准
recall=Recall(train,test,tags,item_tags,user_tags,N,state)
precision=Precision(train,test,tags,item_tags,user_tags,N,state)
coverage=Coverage(train,test,tags,item_tags,user_tags,N,state)
return recall,precision,coverage
data=genData()
train=[]
test=[]
UIT=user_item_tag(data)
train,test=splitData(UIT,train,test)
tags,item_tags,user_tags=Initstate(train)
N=10
for stat in range(1,5):
recall,precision,coverage=evaluate(train,test,tags,item_tags,user_tags,N,stat)
print stat
print("Recall: ", recall)
print("Precision: ", precision)
print("Coverage: ", coverage)
实验结果
1
(‘Recall: ‘, 0.16858299595141701)
(‘Precision: ‘, 0.006946019883899379)
(‘Coverage: ‘, 0.6197057512260365)
2
(‘Recall: ‘, 0.10375168690958164)
(‘Precision: ‘, 0.0042748159516025)
(‘Coverage: ‘, 0.000743052459503641)
3
(‘Recall: ‘, 0.20259109311740892)
(‘Precision: ‘, 0.008347234269700406)
(‘Coverage: ‘, 0.523480457720315)
4
(‘Recall: ‘, 0.28842105263157897)
(‘Precision: ‘, 0.011883632481483953)
(‘Coverage: ‘, 0.6334522217268539)