获取社交网络数据途径
社交网络数据的来源有下面几个:
电子邮件
用户注册信息:比如公司、学校等 (用于冷启动问题)
用户的位置数据:IP地址或者GPS数据
论坛和讨论组 (这个获取的一般是兴趣爱好)
即时聊天工具:QQ
社交网站: Facebook (社交图谱) Twitter (兴趣图谱)
社交网络数据简介
我们用图G(V,E,W)定义一个社交网络:
V是顶点集合,每个顶点是一个用户id
E是边集合,如果Va和Vb有社交关系,即存在E(a,b)
W(a,b)表示边的权重
一般来说,有3种不同的社交网络数据:
双向确认的社交网络数据:一般通过无向图表示
单向关注的社交网络数据:用户关系是单向的,可以通过有向图表示
基于社区的社交网络数据:比如豆瓣小组
基于社交网络的推荐
利用用户的社交网络数据进行推荐优点:
1.好友推荐可以增加推荐的信任度
2.社交网络可以解决冷启动问题
(缺点:由于用户的好友关系可能不是基于共同兴趣产生的,例如a-b是基于b的颜值??所以用户好友的兴趣与用户兴趣不一致)
基于领域的社会化推荐
1)最简单的方法是给用户推荐好友喜欢的物品集合,用户u对物品i的兴趣pui可以通过如下公式计算:
其中out(u)是用户u的好友集合,如果用户v喜欢物品i,则rvi=1,否则为0
2)当然,不同好友之间的熟悉度和兴趣相似度是不一样的,因此应该在推荐的时候把这个考虑在内:
这里的wuv由两部分相似度构成,一部分是用户u和用户v的熟悉程度,另一部分是用户u和用户v的兴趣相似度。
其中,用户u和用户v的熟悉程度由如下公式度量,即他们之间的共同好友比例:
而用户u和用户v的兴趣相似度由如下公式度量,即他们喜欢的物品重合度:
从两方面改进基于邻域的社会化推荐算法
两处截断:
第一处截断:哪用户好友集合时只拿出和用户相似度最高的N个好友
第二处截断:查询用户行为做兴趣相似度时,只返回最近1个月的行为
重新设计数据库
给用户推荐好友
基于内容的匹配
常用内容属性包括:
用户的人口统计学属性(年龄、职业、性别等);
用户的兴趣(喜欢的物品和发布过的言论);
用户的位置信息(用户住址、邮编、IP等);
基于共同兴趣的好友推荐
利用UserCF的思想,如果两个用户喜欢相同的物品(比如同一条微博),就说明他们具有相似的兴趣;此外,也可以根据用户在社交网络中的评论提取用户的兴趣标签,来计算用户的兴趣相似度。
基于社交网络图的好友推荐
基于社交网络图的好友推荐
out(u)是在社交网络图中用户u指向的其他好友的集合
in(u)是在社交网络图中指向用户u的用户集合
通过用户u和用户v的出度和入度,定义W。根据相似度W进行推荐
计算相似度方法的解释在最后代码里
有下面几种方法计算相似度:
1.用户u,v的共同好友比例来计算相似度
def FriendSuggestion_out(u,G_out,G_in): suggestions = dict() G_out.setdefault(u,set()) G_in.setdefault(u,set()) friends = G_out[u] # i = 0 for u_friend in G_out[u]: # i += 1 for u_friend_friend in G_in[u_friend]: if u_friend_friend in friends: continue suggestions.setdefault(u_friend_friend,0) suggestions[u_friend_friend] += 1 for i,j in suggestions.items(): if i == u: continue if len(G_out[i]) == 0: suggestions[i] = 0 else: suggestions[i] = j / math.sqrt(len(G_out[u]) * len(G_out[i])) # return dict(sorted(suggestions.items(),key=itemgetter(1),reverse=True)[:k]) return suggestions
2.关注u,v的用户的集合交集计算相似度
def FriendSuggestion_in(u,G_out,G_in): suggestions = dict() G_out.setdefault(u,set()) G_in.setdefault(u,set()) friends = G_out[u] # i = 0 for u_friend in G_in[u]: # i += 1 for u_friend_friend in G_out[u_friend]: if u_friend_friend in friends: continue suggestions.setdefault(u_friend_friend,0) suggestions[u_friend_friend] += 1 # print(i) # suggestions[u_friend] = suggestions[u_friend_friend] for i,j in suggestions.items(): if i == u: continue if len(G_in[i]) == 0: suggestions[i] = 0 else: suggestions[i] = j / math.sqrt(len(G_in[u]) * len(G_in[i])) return suggestions
3.u关注的用户中,有多大比例也关注用户v,同时施加惩罚in(v)来计算相似度
(考虑到某一名人,存在很多粉丝,导致每个人都与名人有很大相似度 例如有一亿粉丝的何老师~)
def FriendSuggestion_mix(u,G_out,G_in): suggestions = dict() G_out.setdefault(u,set()) G_in.setdefault(u,set()) friends = G_out[u] for u_friend in G_out[u]: for u_friend_friend in G_out[u_friend]: if u_friend_friend in friends: continue suggestions.setdefault(u_friend_friend,0) suggestions[u_friend_friend] += 1 # suggestions[u_friend] = suggestions[u_friend_friend] for i,j in suggestions.items(): if len(G_in[i]) == 0: suggestions[i] = 0 else: suggestions[i] = j / math.sqrt(len(G_out[u]) * len(G_in[i])) return suggestions
实现给用户推荐好友的完整过程代码
import os import math from operator import itemgetter from sklearn.model_selection import train_test_split import random #获取文件列表 取前200个文件¶ edges = [name for name in os.listdir('twitter/') if name.endswith(".edges")] #edges[:5] train_G_out = dict() test_G_out = dict() train_G_in = dict() test_G_in = dict() #获取文件名的ID 以及.edges文件里的id 得到out in 两个字典 for file in edges[:200]: with open('twitter/' + file) as f: lines = f.readlines() for line in lines: a,b = line.split(" ") b = b.strip("\n") if random.random() < 0.8: #划分数据集 train_G_out.setdefault(file[:-6],set()) train_G_out.setdefault(a,set()) train_G_out.setdefault(b,set()) train_G_out[file[:-6]].add(a) train_G_out[file[:-6]].add(b) train_G_out[a].add(b) train_G_in.setdefault(file[:-6],set()) train_G_in.setdefault(a,set()) train_G_in.setdefault(b,set()) train_G_in[a].add(file[:-6]) train_G_in[b].add(a) train_G_in[b].add(file[:-6]) #str else: test_G_out.setdefault(file[:-6],set()) test_G_out.setdefault(a,set()) test_G_out.setdefault(b,set()) test_G_out[file[:-6]].add(a) test_G_out[file[:-6]].add(b) test_G_out[a].add(b) test_G_in.setdefault(file[:-6],set()) test_G_in.setdefault(a,set()) test_G_in.setdefault(b,set()) test_G_in[a].add(file[:-6]) test_G_in[b].add(a) test_G_in[b].add(file[:-6]) #str def FriendSuggestion_out(u,G_out,G_in): suggestions = dict() G_out.setdefault(u,set()) G_in.setdefault(u,set()) friends = G_out[u] # i = 0 for u_friend in G_out[u]: #遍历用户u关注的好友 # i += 1 for u_friend_friend in G_in[u_friend]: #u关注的好友中的粉丝列表 if u_friend_friend in friends: #若粉丝是u关注的好友就跳过 continue suggestions.setdefault(u_friend_friend,0) suggestions[u_friend_friend] += 1 #对于u关注的好友的粉丝与u有一个交集 进行+1 for i,j in suggestions.items(): if i == u: #去除本身 suggestions[i] = 0 elif len(G_out[i]) == 0: suggestions[i] = 0 else: suggestions[i] = j / math.sqrt(len(G_out[u]) * len(G_out[i])) # return dict(sorted(suggestions.items(),key=itemgetter(1),reverse=True)[:k]) return suggestions def FriendSuggestion_in(u,G_out,G_in): suggestions = dict() G_out.setdefault(u,set()) G_in.setdefault(u,set()) friends = G_out[u] # i = 0 for u_friend in G_in[u]: #遍历关注用户u的粉丝 # i += 1 for u_friend_friend in G_out[u_friend]: #u的粉丝的关注列表好友 if u_friend_friend in friends: continue suggestions.setdefault(u_friend_friend,0) suggestions[u_friend_friend] += 1 #uv的粉丝交集 +1 # print(i) # suggestions[u_friend] = suggestions[u_friend_friend] for i,j in suggestions.items(): if i == u: suggestions[i] = 0 elif len(G_in[i]) == 0: suggestions[i] = 0 else: suggestions[i] = j / math.sqrt(len(G_in[u]) * len(G_in[i])) return suggestions def FriendSuggestion_mix(u,G_out,G_in): suggestions = dict() G_out.setdefault(u,set()) G_in.setdefault(u,set()) friends = G_out[u] for u_friend in G_out[u]: #遍历u关注的好友列表 for u_friend_friend in G_out[u_friend]: #遍历u好友的关注列表 即u关注的好友是u_friend_friend的粉丝 if u_friend_friend in friends: continue suggestions.setdefault(u_friend_friend,0) suggestions[u_friend_friend] += 1 #即u关注的好友有多大比例是用户v的粉丝 交集+1 # suggestions[u_friend] = suggestions[u_friend_friend] for i,j in suggestions.items(): if i == u: suggestions[i] = 0 elif len(G_in[i]) == 0: suggestions[i] = 0 else: suggestions[i] = j / math.sqrt(len(G_out[u]) * len(G_in[i])) return suggestions def recommend(u,G_out,G_in,k,choice): if choice == 'out': suggestions = FriendSuggestion_out(u,G_out,G_in) elif choice == 'in': suggestions = FriendSuggestion_in(u,G_out,G_in) else: suggestions = FriendSuggestion_mix(u,G_out,G_in) return dict(sorted(suggestions.items(),key=itemgetter(1),reverse=True)[:k]) def precision(k,choice): right = 0 predict = 0 for u in test_G_out.keys(): x = recommend(u,train_G_out,train_G_in,k,choice) for i in x.keys(): if i in test_G_out[u]: right += 1 predict += k ans = right / (predict * 1.0) return ans * 100 #为用户‘100318079’推荐 print(recommend('100318079',train_G_out,train_G_in,5,'out')) #验证测试集正确率 print("正确率:%.2f%%"%(precision(4,'mix'))) #{'217796457': 0.36794648440311994, # '261753869': 0.3611730459561101, # '92336981': 0.3611730459561101, # '77618627': 0.35781322366606716, # '540912889': 0.3517811819867572} #正确率:19.80%