Facebook社交网络R语言分析
本文将基于facebook的好友关系数据,研究用户分布规律,并提供简单的好友推荐算法。
数据来源
KONECT1 http://konect.uni-koblenz.de/networks/facebook-wosn-links
数据原始格式
. txt文本格式,空格分隔
. 注释信息以%开头
. 每行一组数据,共四个字段
第一字段:用户ID1
第二字段:用户ID2
第三字段:用途不明
第四字段:好友关系建立时间,多数为0,数据缺失
% sym unweighted
% 817035 63731 63731
1 2 1 0
1 3 1 0
1 4 1 0
2 3 1 1183325626
2 7 1 0
2 9 1 1187651286
...
Note:好友信息以无向图的形式存储,不存在重复链接,保证第一字段用户ID始终小于第二字段用户ID;从实例数据中我们可以看到用户1和用户2是好友,但只存在于用户1的好友记录里,而不会在用户2的好友记录里重复出现
数据清洗
需要从原始数据中清除这些:
- 以%开头的注释行
- 不明用途的第三字段
- 数据缺失的第四字段
# 利用linux命令sed,awk完成数据清洗cat facebook-wosn-links.txt | sed '/%/d' |
awk '{print $1" "$2}' > facebook-wosn-links-clean.txt
数据读入
利用R语言read.table函数以table格式存储数据
# R语言读入数据friends.whole <- read.table("Your File Address",
header=FALSE, sep=" ", col.names=c("from","to"))
数据选取
数据中包含非常多的用户,数据间相互影响,为了使结果更清晰,我们选定某一用户,分析其好友的分布特点
library(igraph)# 将所有用户按照好友数量倒序排序sort(table(c(friends.whole$from, friends.whole$to)), dec=T)# 选定拥有合适好友数量的用户uid <- 979# 好友IDfriends.connected <- unique(c(friends.whole$to[friends.whole$from == uid],
friends.whole$from[friends.whole$to == uid]))# 选取该用户所有好友friends.sample <- friends.whole[
((friends.whole$from %in% friends.connected) &
(friends.whole$to %in% friends.connected)), c(1,2)]# 创建graph对象,并去除循环friends.graph <- graph.data.frame(d = friends.sample,
directed = F, vertices = unique(c(friends.sample$from,
friends.sample$to)))
friends.graph <- simplify(friends.graph)
is.simple(friends.graph)# 去除孤立的点,其实本例中并不存在孤立点,但作为标准化操作保留dg <- degree(friends.graph)
friends.graph <- induced.subgraph(friends.graph,
which(dg > 0))
好友分布图
plot(friends.graph, layout = layout.fruchterman.reingold,
vertex.size = 2.5, vertex.label = NA, edge.color =
grey(0.5), edge.arrow.mode = "-")
接下来,我们希望将不同群体的好友用不同的颜色标明出来,提供类似于好友自动分组的功能;使用的是igraph包提供的walktrap.community函数2
friends.com = walktrap.community(friends.graph, steps=10)# 返回每个节点的分组结果V(friends.graph)$sg = friends.com$membership# 按照分组结果赋予节点不同的颜色V(friends.graph)$color = NA
V(friends.graph)$color = rainbow(max(V(friends.graph)$sg))[V(friends.graph)$sg]
plot(friends.graph, layout = layout.fruchterman.reingold,
vertex.size = 5, vertex.color = V(friends.graph)$color,
vertex.label = NA, edge.color = grey(0.5), edge.arrow.mode = "-")
在图中,有些用户是中间人的角色,连接了两个聚集,我们可以利用igraph包提供的betweenness函数找出他们
V(friends.graph)$btn = betweenness(friends.graph, directed = F)
plot(V(friends.graph)$btn, xlab="Vertex", ylab="Betweenness")
betweenness函数统计的是通过每个节点的最短路径的数量,该值越高,则表明该节点作为中间节点的作用越强
从图上看出,有3个节点的betweenness值明显高于其他节点,因此我们可以选取betweenness值500为阙值将这3个节点在图上标明出来
V(friends.graph)$size = 5V(friends.graph)[btn>=500]$size = 15V(friends.graph)$label = NA
V(friends.graph)[btn>=500]$label = V(friends.graph)[btn>=500]$name
plot(friends.graph, layout = layout.fruchterman.reingold,
vertex.size = V(friends.graph)$size,
vertex.color = V(friends.graph)$color,
vertex.label = V(friends.graph)$label,
edge.color = grey(0.5),
edge.arrow.mode = "-")
最后,我们希望从二级好友3中找出一些用户来进行推荐,可以根据共同好友数量来选取
# 所有二级好友friends.2nd <- c(friends.whole$from[
(friends.whole$to %in% friends.connected)],
friends.whole$to[
(friends.whole$from %in% friends.connected)])# 该用户本身也会被包含到二级好友中,需要剔除friends.2nd <- friends.2nd[friends.2nd!=uid]# 按共同好友的数量进行倒序排序friends.recommand <- sort(table(friends.2nd), dec = T)# 取出共同好友最多的10个用户来推荐friends.recommand <- friends.recommand[1:10]
> friends.recommand[1:10]
friends.2nd
用户ID 5050 5559 6896 5587 7659 6255 14521 554 5586 6062 共同好友数量 63 22 20 19 18 17 16 15 15 15
根据共同好友数量的推荐算法虽然较为简单,但只要网络本身包含较多的真实线下好友关系,推荐的结果还是非常有价值的。此外,还有许多推荐算法,如根据用户的属性(兴趣爱好,地理位置等)来做聚类推荐,我们将在以后的文章中进行探讨。
- ASP.NET MVC中的ActionFilter是如何执行的?
- C语言嵌入式系统编程修炼之屏幕操作
- max-width:100%在td或者table-cell里渲染不符合预期小笔记
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
- 使用Ansible自动化您的(云或者本地)机器
- 像Apache Storm一样简单的分布式图计算
- css绘图,实现一些特殊形状
- 看机器学习如何还原图像色彩
- CSS Hack整理
- 如何在调用WCF服务之前弹出一个确认对话框?
- 表格列的hover状态与选中状态
- 神级程序员教你如何写代码——十年编程内功心法
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
- Web-Fontmin -- 在线提取你需要的字体
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 微服务[学成在线] day13:使用FFmpeg进行格式转换以及m3u8文件生成、文件分块上传接口实现
- GTID,你了解多少?
- Spring Boot 拓展SpringMVC
- Spring Boot 日志配置
- R语言进阶之图形参数
- 第04期:Prometheus 数据采集(三)
- 技术分享 | Online DDL 工具 gh-ost
- Spring Boot 整合Mybatis
- R语言进阶之时间序列分析
- Spring Boot 实现员工信息管理demo
- 如何把 Flutter 云端一体化做到极致?
- 微服务[学成在线] day16:基于Spring Security Oauth2开发认证服务
- 新的跨域策略:使用COOP、COEP为浏览器创建更安全的环境
- CVE-2020-1948:Dubbo Provider默认反序列化复现
- R语言进阶之因子分析