目录

  1. igraph 包简介
  2. 社交网络分析应用场景
  3. 社交网络的基本知识
  4. 社交网络的常见结构
  5. 社交网络分析算法
  6. 使用社交网络分析分析微博水军

0.igraph 简介

igraph 是一系列网络分析工具,其强调效率,便携性和易用性,其不仅仅支持C/C++直接调用,同时还提供了R,python,Ruby等语言接口,其主要的功能是无向图,有向图的算法,包含生成图,最短路径,生成最小树等经典算法,还包含了计算中介中心性,网络分析等算法。

igraph库的主要目标是提供一组数据类型和函数,1)高效实现图算法,2)快速处理大图,具有数百万个顶点和边,3)给其他语言提供借口,进行快速原型设计

Igraph是免费开源的,其官网如下:

https://igraph.org/

R可以通过 igraph这个包来调用这个网络工具

准备工作

首先我们需要安装好这个包,使用’’’install.packages(“igraph”)```进行安装,安装好了这个包之后我们需要加载这个包。

library(igraph)
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union

1.社交网络分析的应用场景

社交网络分析是一种无监督的机器学习方法,有一些类似于机器学习中的聚类算法,用于识别社交圈子。所谓物以类聚,人以群分,一旦我们可以将社交网络划分成为不同的圈子,就可以有很多的应用。

例如:

  1. 微信和QQ是关于人与人之间的强关系网络,对微信和QQ的社交网络进行分析,识别出不同的网络圈,一个应用场景是朋友相互推荐。
  2. 微博,豆瓣是社交网络中关注与被关注的弱关系网络,社交网络分析可以有助于消息和知识的传播
  3. 社交网络分析还可以对用户进行精准化营销,个性化推荐商品和服务。因为同一个社交网络里面的人群是相似的,因此可以同一个社交群体里面推荐相同的产品或者服务
  4. 疾病传播也是属于社交网络的模型,因此对疾病传播网络的分析可以识别关键节点,并且切断网络中的关键节点以阻止传染疾病的传播
  5. 还可以帮助金融机构识别欺诈集团,进行反欺诈风控

还有很多可以应用的领域

2.社交网络的基本知识

社交网络通常使用图来描述,图可以非常直观的描述事物之间的关系。在图中,节点(node)表示一个人,或者一个事物,边(edge)代表人或者事物之间的关系。有向图用箭头表示事物之间的关系,无向图直接使用线段来描述.

关于图,有几个重要的概念:

  1. 度(Degree)

这个概念是用来描述连接点(vertices)的活跃性,指的是与点相连接的边的数目。在有向图中,还区分为出度(out degree)和入度(in degree)。出度指的是以某一个节点为起点指向另外一个点的边的数目。入度指的是以某一个节点为终点的边的数目。有向图某个节点的度(degree)是出度和入度的和。

  1. 边(edges)

边分为有向边和无向边

  1. 图的密度

计算的公式是整个图的边数处以整个图可能的边数

这里举一个简单的例子来看一下:

第一步,构造一个网络

构造一个简单的网络

构造一个网络一般会使用两个函数:

  1. graph
  2. graph.data.frame

首先使用graph进行构建网络,首先我们来查看一下graph的使用方法?graph

myfristnewwork <- graph(edges = c("Alice","Sam","Sam","Sam","Sam","David","David","Alice","Frank","David"),directed = TRUE)

# 进行绘图

plot(myfristnewwork)

myfristnewwork[]

## 4 x 4 sparse Matrix of class "dgCMatrix"
##       Alice Sam David Frank
## Alice     .   1     .     .
## Sam       .   1     1     .
## David     1   .     .     .
## Frank     .   .     1     .

directed 参数的含义表明我们的图是否是一个有向图。edges传入一个响亮,向量里面的元素两两一组,构成一个链接

然后我们使用graph.data.frame这个函数来构建图

myfristnewwork <- graph.data.frame(data.frame(c("Alice","Sam","Sam","David","Frank"),c("Sam","Sam","David","Alice","David")))

plot(myfristnewwork)

myfristnewwork[]
## 4 x 4 sparse Matrix of class "dgCMatrix"
##       Alice Sam David Frank
## Alice     .   1     .     .
## Sam       .   1     1     .
## David     1   .     .     .
## Frank     .   .     1     .

使用graph.data.frame这个函数来构建网络需要传递一个数据框,这个数据框有两列,这两列一一对应,构成网络,其中,默认是,directed = TRUE,其表明是有向图,

计算图的度

有了有向图,可以通过degree函数进行查看图的度数,直接输入网络图,可以查看整个图的总度数

degree(myfristnewwork)
## Alice   Sam David Frank 
##     2     4     3     1

查看某一个节点的度数

degree(myfristnewwork,v = "Alice")
## Alice 
##     2

如果想知道网络图中有哪些节点,可以使用V()

V(myfristnewwork)
## + 4/4 vertices, named, from b8a2fee:
## [1] Alice Sam   David Frank

计算出度与如度

degree(myfristnewwork,mode = "in")
## Alice   Sam David Frank 
##     1     2     2     0
degree(myfristnewwork,mode = "out")
## Alice   Sam David Frank 
##     1     2     1     1

计算图的顶点数和边数

vcount(myfristnewwork)
## [1] 4
ecount(myfristnewwork)
## [1] 5

整个图的路径长度

diameter(myfristnewwork,directed = F,weights = NA)
## [1] 2

使用这个函数可以得到图的最长的路径

图的密度

edge_density(myfristnewwork)
## [1] 0.4166667

计算的公式是整个图的边数处以整个图可能的边数

ecount(myfristnewwork)
## [1] 5
ecount(myfristnewwork)/(vcount(myfristnewwork)*(vcount(myfristnewwork)-1))
## [1] 0.4166667

这里通过顶点数量与边的数量计算了整个图的密度

3.社交网络的常见结构

特定图模型的构建

  1. 空图
eg <- make_empty_graph(40)

plot(eg, vertex.size=10, vertex.label=NA)

  1. 全连接的图
fg <- make_full_graph(40)

plot(fg, vertex.size=10, vertex.label=NA)

  1. 星图
st <- make_star(40)

plot(st, vertex.size=10, vertex.label=NA)

  1. 树图
tr <- make_tree(40, children = 3, mode = "undirected")

plot(tr, vertex.size=10, vertex.label=NA)

  1. 环图
rn <- make_ring(40)

plot(rn, vertex.size=10, vertex.label=NA)

  1. Erdos-Renyi random graph model(鄂尔多随机图)
er <- sample_gnm(n=100, m=40) 

plot(er, vertex.size=6, vertex.label=NA)  

  1. Watts-Strogatz(瓦-斯托加茨)
sw <- sample_smallworld(dim=2, size=10, nei=1, p=0.1)

plot(sw, vertex.size=6, vertex.label=NA, layout=layout_in_circle)

这里使用的是plot函数进行绘图,plot是范型函数,在这里调用plot其实是调用plot.graph,这里介绍一下绘图的参数:

比如我们想要修改颜色

plot(myfristnewwork,vertex.color="red")

去掉节点的标识

plot(myfristnewwork,vertex.color="red",vertex.label = c("a","b","c"))

4. 社交网络分析算法

在我们开始之前,我们需要将我们的网络图转化成为无向图,最常用的方法是使用as.undirected

myfristnewwork_undirected<- as.undirected(myfristnewwork)

plot(myfristnewwork)

plot(myfristnewwork_undirected)

另外一种就是在创建图的时候就直接指定无向图:

myfristnewwork1 <- graph(edges = c("Alice","Sam","Sam","Sam","Sam","David","David","Alice","Frank","David"),directed = FALSE)

plot(myfristnewwork1)

社区检测

Newman-Girvan

第一个介绍的方法是基于边界介于中间的社区检测(Newman-Girvan)

GGirvan-Newman算法通过不断地删除网络中的边来检测网络中的社区。在最终剩余的网络中的连通分量也就是社区。Girvan-Newman算法并不是去测量哪些边具有最高的中心度,而是去关注哪些最有可能连接着社区。

顶点介数是一种反应网络中顶点的中心度的指标。对于一个顶点i,顶点介数是指网络中经过该顶点的所有最短路径的数量。

Girvan-Newman算法将介数扩展到了边。类似地,一条边的边介数是指网络中经过该边的最短路径的数量。如果一个网络所包含的社区之间是由少量的边连接的,那么经由不同社区的最短路径都需要从这些边上经过,因此这些边的边介数会非常高。通过移除这些边,各个社区之间将会被分割开来,从而可以发现这些社区。

Girvan-Newman算法的步骤如下:

重新计算剩余每条边的边介数需要不少计算时间,然而,并没有较好的办法省去这些开销。当一条边被删除了之后,网络的结构发生了变化,举个例子来说,假设两个社区之间有不止一条边连接,那么并不是每条边都会有较高的边介数,我们只能逐渐地删除这些边,在这个过程中会发现至少有一条边会有较高的边介数。

Girvan-Newman算法的结果是一个树状图。这个树状图自顶向下地描绘了社区的结构。树状图的叶子则是图的每个结点。

g <- tr <- make_tree(40, children = 3, mode = "undirected")
 # 首先构造一个网络
plot(g)

ceb <- cluster_edge_betweenness(g) # 构造模型
dendPlot(ceb) # 可视化

plot(ceb,g)

ceb
## IGRAPH clustering edge betweenness, groups: 7, mod: 0.68
## + groups:
##   $`1`
##   [1]  1  4 13 38 39 40
##   
##   $`2`
##   [1]  2  6  7 17 18 19 20 21 22
##   
##   $`3`
##   [1]  3  9 10 26 27 28 29 30 31
##   
##   $`4`
##   + ... omitted several groups/vertices

可以看到,这里将网络划分成为了7个社群

基于传播标签的社区检测

这种方法的基本思想是:每一个点的社群归属是由相邻的节点标签决定的,相邻节点中出现最多的那个标签就是该节点的标签。类似于机器学习中的KNN算法。

在最一开始,每一个节点都有一个独特的标签,然后密集链接的节点标签归位一类,然后进行不断的迭代,直到这些具有相同标签的节点组成一个社群。

clp <- cluster_label_prop(g)
plot(clp,g)

基于贪婪优化模块的社区检测

基于贪婪优化模块的社区检测 是另一种分层方法,但它是自下而上而不是自上而下。它试图以贪婪的方式优化称为模块化的质量功能。最初,每个顶点属于一个单独的社区,并且迭代地合并社区,使得每个合并是局部最优的(即,产生模块化的当前值的最大增加)。当不可能再增加模块性时,算法停止,因此它为您提供分组和树形图。该方法很快,并且它通常作为第一近似尝试的方法,因为它没有要调整的参数。然而,已知会受到分辨率限制,即低于给定大小阈值的社区(取决于节点和边缘的数量,如果我没记错的话)将始终与邻近社区合并。

cfg <- cluster_fast_greedy(g)

自旋转玻璃社群

自旋玻璃源于物理学,他是某些特制的物理材料的一种无序状态,如果把关系网络看成一个随机网络场,网络中某一节点与其他节点链接或者不连接,可以看作磁性材料相互作用与反磁性相互作用,两种相互作用形成一个能力的函数,当能量函数小的时候,关系网络的层次结构被解释称为旋转配置,此时网络内部的社群可看作自旋转系统的状态,该过程类似于层次聚类。

sping <- spinglass.community(g)

plot(sping,g)

案例

这个安利的数据来自于weibo数据,在weibo数据中,存在一些用户是spammer,我们称这类用户为垃圾用户。数据已经有了部分的标签。我们尝试对weibo的用户数据进行社交网络分析,划分出不同的社交网络群体

首先我们需要读取数据

require(tidyverse)
follower<- readr::read_csv("/Users/milin/Downloads/microblogPCU/follower_followee.csv")
post <- readr::read_csv("/Users/milin/Downloads/microblogPCU/post.csv")

user_post <- readr::read_csv("/Users/milin/Downloads/microblogPCU/user_post.csv")

weibo_user <- readr::read_csv("/Users/milin/Downloads/microblogPCU/weibo_user.csv")




dim(follower)
## [1] 142368     10
dim(post)
## [1] 35 11
dim(user_post)
## [1] 48813     9
dim(weibo_user)
## [1] 781  10
load(file = "/Users/milin/Downloads/兼职/id1.RData")

数据集的属性信息:

weibo_user.csv

user_post.csv

followe-followee.csv

post.csv和user_post.csv类似

现在取出来一部分建立关系图

library(igraph)
library(Hmisc)
## Loading required package: lattice
## Loading required package: survival
## Loading required package: Formula
## 
## Attaching package: 'Hmisc'
## The following objects are masked from 'package:dplyr':
## 
##     src, summarize
## The following objects are masked from 'package:base':
## 
##     format.pval, units
follower <- follower %>% filter(follower_id %nin% id1)
follower_followee_part <- follower[1:1000,]
gg<-graph.data.frame(data.frame(er=follower_followee_part$follower_id,ee=follower_followee_part$followee_id))  
plot(gg,  
     vertex.label=NA,      ##不显示标签  
     edge.arrow.mode='-',  ##不使用箭头  
     vertex.size = 5       ##设置结点圆的大小  
     )  

第一种方法:自旋转玻璃社群

自旋玻璃源于物理学,他是某些特制的物理材料的一种无序状态,如果把关系网络看成一个随机网络场,网络中某一节点与其他节点链接或者不连接,可以看作磁性材料相互作用与反磁性相互作用,两种相互作用形成一个能力的函数,当能量函数小的时候,关系网络的层次结构被解释称为旋转配置,此时网络内部的社群可看作自旋转系统的状态,该过程类似于层次聚类。

sping <- spinglass.community(gg)
plot(sping,gg,vertex.label=NA,      ##不显示标签  
     edge.arrow.mode='-',  ##不使用箭头  
     vertex.size = 5 )      ##设置结点圆的大小 )

sping$membership
##   [1]  7 10  8  6  4  2  5 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
##  [24] 11 11 11 11 11 11  8 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
##  [47] 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  7  7
##  [70]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
##  [93]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7 10 10 10 10  8  8
## [116]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
## [139]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
## [162]  8  8  8  8  8  8  8  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
## [185]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
## [208]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
## [231]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  4  4  4
## [254]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
## [277]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  2  2  2  2  2  2  2  2
## [300]  2  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
## [323]  5  5  5  5 11 11 11  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
## [346]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
## [369]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
## [392]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
## [415]  7  7  7  7  7  7  7  7  7  7  7 10 10 10 10 10 10 10 10 10 10 10 10
## [438] 10 10 10 10 10 10 10 10 10 10  2  2 10 10 10 10 10 10 10 10 10 10 10
## [461] 10 10 10 10 10 10 10 10  2 10 10 10 10 10 10 10 10 10 10 10 10 10 10
## [484] 10 10 10 10 10 10 10  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
## [507]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
## [530]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
## [553]  8  8  8  8  8  1  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
## [576]  8  8  8  8  8  8  8  8  8  6  6  6  6  6  6  6  6  6  6  6  6  6  6
## [599]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
## [622]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
## [645]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  9
## [668]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  4 11  4  4  4  4  4
## [691]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
## [714]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
## [737]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
## [760]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
## [783]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
## [806]  2  2  2  2  2  2  5  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
## [829]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
## [852]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  5  5  5  5
## [875]  5  5  5  5  5  5 12  5  5  5  5  5  5  3  5  5  5  5  5  5  5  5  5
## [898]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
## [921]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  1  5  5  5  5  5  5  5  5
## [944]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
weibo_user$user_id <- as.character(weibo_user$user_id)
social <- data.frame(sping$names,sping$membership)
social$sping.names <- as.character(social$sping.names)
social <- social %>% left_join(weibo_user[,c(1,10)],by=c("sping.names"="user_id"))


table(social$sping.membership,social$is_spammer,useNA = "always")
##       
##         -1   1 <NA>
##   1      0   0    2
##   2      1   0   99
##   3      0   0    1
##   4      0   1  139
##   5      1   0  113
##   6      0   1  180
##   7      0   1  138
##   8      0   1  149
##   9      0   0    1
##   10     0   0   67
##   11     0  16   47
##   12     0   0    1
##   <NA>   0   0    0

可以看到,关系网络划分成为了10个群体,其中第8个群体是spammer群体

第二种方法:Community structure detection based on edge betweenness

基于边缘中介的社区结构检测

weibo_network<-graph.data.frame(data.frame(er=follower_followee_part$follower_id,ee=follower_followee_part$followee_id),directed = F)  

clus <- cluster_edge_betweenness(weibo_network)

plot(clus,weibo_network,vertex.label=NA,      ##不显示标签  
     edge.arrow.mode='-',  ##不使用箭头  
     vertex.size = 5 )      ##设置结点圆的大小 )

查看社群的分类

clus$membership
##   [1] 1 2 3 4 5 6 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 3 8 8 8 8 8
##  [36] 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 1 1 1
##  [71] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [106] 1 1 1 1 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [141] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4
## [176] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [211] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [246] 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
## [281] 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
## [316] 7 7 7 7 7 7 7 7 7 7 7 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [351] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [386] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [421] 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 7 2 2 2 2 2 2 2 2 2 2 2
## [456] 2 2 2 2 2 2 2 7 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 7 2
## [491] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [526] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [561] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4
## [596] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [631] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [666] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
## [701] 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
## [736] 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
## [771] 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [806] 6 7 6 6 6 6 7 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
## [841] 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7
## [876] 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
## [911] 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
## [946] 7 7 7 7 7 7 7 7 7 7 7 7 7 7
social <- data.frame(clus$names,clus$membership)
social$clus.names <- as.character(social$clus.names)
social <- social %>% left_join(weibo_user[,c(1,10)],by=c("clus.names"="user_id"))


table(social$clus.membership,social$is_spammer,useNA = "always")
##       
##         -1   1 <NA>
##   1      0   1  138
##   2      0   0   67
##   3      0   1  150
##   4      0   1  181
##   5      0   1  140
##   6      1   0   95
##   7      1   0  120
##   8      0  16   46
##   <NA>   0   0    0

可以看到,关系网络划分成为了8个群体,其中第8个群体是spammer群体