美文网首页
facebook社交网络分析

facebook社交网络分析

作者: 小小孩儿的碎碎念 | 来源:发表于2019-01-10 23:14 被阅读99次

    1 数据介绍

    1.1 数据背景

    该数据集来源于斯坦福大型网络数据集网站(http://snap.stanford.edu/data/ego-Facebook.html),由facebook的朋友列表组成,facebook上用户间的社交网络,共有节点数4039个,边缘数88233条。

    1.2 数据预处理

    本社交网络分析案例是基于R 语言程序实现的。原始数据为.txt文件,读入R语言中,展示如下:

    建立社交网络关系图:

    代码如下:

    g <- graph.data.frame(facebook)#加载数据框jpeg(filename='facebook.jpg',width=2000,height=2000,units='px')#生成图片,大小是2000*2000px

    plot(g,   

    vertex.size=2, #节点大小

    layout=layout.fruchterman.reingold, #布局方式

    vertex.shape='circle', #带边框

    vertex.label.cex=0.5, #节点字体大小

    vertex.label.color='black', #节点字体颜色

    edge.arrow.size=0) #连线的箭头的大小

    dev.off() #关闭图形设备,将缓冲区中的数据写入文件

    建立某个人的社交网络关系图,以其中某4个人为例:

    建立某个用户的二层社交网络关系图:

    同时建立某两个人的社交网络关系图:

    根据联系人的多少决定节点的大小和色彩,连线设成弧线,如下图:

          邻接矩阵即反映节点之间是否有连边的方形矩阵,维度为结点的个数,如果两个结点之间有连边,则矩阵中相应的位置为1,没有连边则为0。无向网络的邻接矩阵是对称矩阵,而有向网络的邻接矩阵是非对称矩阵。将数据转换成邻接矩阵如下:

    代码如下:

    g1<-graph.data.frame(as.matrix(facebook))

    g2<-get.adjacency(g1,sparse=FALSE) ###转换为邻接矩阵

    2 统计特征分析

    2.1 网络基本属性

    我们发现网络的网络的节点个数为4029,边条数为88233,为有向网络。网络密度用来形容网络的结构复杂程度,越大说明网络越复杂,网络越能够放在一块,facebook社交网络的网络密度为0.00540992,说明该网络不是很容易聚一块儿。该网络的直径为17,整个网络的平均距离为4.337746。

    2.2 度分布

    节点的度:度越大,该节点越重要,就facebook朋友间社交网络而言,度越大,表示与该用户相联系的用户越多。经计算,我们发现,最小的度为1,节点数为75,最大的度为1045,节点数为1。该facebook社交网络为有向网络,故又分为入度和出度。就入度而言,最小入度为2,节点数为1。最大入度为1134,节点数为5。就出度而言,最小出度为1,节点数为16,最大出度为1134,节点数为6。

    度分布:

    degree.distribution(g)

    plot(degree.distribution(g))

    入度与出度:

    2.3 网络聚类系数

    网络聚类系数可以衡量网络中关联性如何,值越大代表交互关系越大。说明网络越复杂,越能放在一块儿聚类。Facebook社交网络的网络聚类系数为0.5191893;网络的平均聚类系数为0.6169473;每个节点的聚类系数如下图(截取部分):

    2.4 节点重要性

    (1)点的中心度

    用于描述在某个点上,有多少条线,强调某点单独的价值。

    (截取部分如下):

    (2)中间中心度

    代表最短距离是否都经过该点,如果都经过说明这个点很重要,其中包括线的中心度。强调点在其他点之间调节能力,控制能力指数,中介调节效应。

    点的中间中心度(截取部分如下):

    线的中间中心度(截取部分如下):

    (3)接近中心度

    接近中心度,用于描述该点与网络中其他点距离之和的倒数,越大说明越在中心,越能够很快到达其他点,强调点在网络的价值。

    截取部分如下:

    (4)特征向量中心度

    根据相邻点的重要性来衡量该点的价值。首先计算邻接矩阵,然后计算邻接矩阵的特征向量。强调点在网络的价值,并且比接近中心度厉害的是,点价值是根据近邻点来决定的。

    截取部分如下:

    (5)排序

    将节点中心度、接近中心度、中间中心度、特征向量中心度排序如下:

    我们发现,在facebook社交网络中,拥有低“特征向量中心度”和高“中间性”的人是很重要的联系人,而拥有高“特征向量中心度”和低“中间性”的人与重要的人有关联。

    2.5社区结构

    社群划分跟聚类差不多,社群内边密度要高于社群间边密度,社群内部连接相对紧密,各个社群之间连接相对稀疏。

    1、 社区划分

    上图图1为我们将社区划分为8个,图2为在划分完的社区中,社区成员1构成的网络关系图。

    2、 基于随机游走的社区划分

    随机游走,利用距离相似度,用合并层次聚类方法建立社群,其特点是运行时间短,但是效果不是特别好,也会出现某类巨多。从中我们可以看出facebook社交网络被划分为了68个社区。

    从图中可以直观地看出好友网络已经被划分为若干相对独立的子群

    查看不同子群中的成员如下,以其中两个子群为例:

    查看起中介作用的好友,画出散点图如下:

    3、 基于点连接的社区发现

    点连接为某点与某社群有关系就是某社群的,通常社区划分效果最差,常常是某一大类超级多。对于该facebook社交网络来说,因其为有向图,所以分为强关联与弱关联,两点间有双向连线为强关联,有单向连线,则为弱关联。

    3 链接预测

    我选择的是基于邻居的相似度指标进行链路预测。

    根据基于邻居的8种相似度链路预测算法的AUC值的对比,RA指标的AUC值在各种情况下都表现较优,因此选择RA指标来进行链路预测。

    此处考虑最简单的情况,每一个起传递作用的中间节点都有一个单位资源,将资源等可能的分配给它所有邻居节点,因此相似度定义为:节点i从j接受到的资源总量(同样为节点j从i接收到的资源总量)。计算公式为:

    算法过程:

    (1)首先按照8:2的比例划分训练集和测试集,并得到训练集邻接矩阵和测试集邻接矩阵;

    (2)得到未观测边集、测试边集和未存在边集;

    (3)得到每个训练集中,节点的邻居节点;

    (4)得到未观测边连接的两节点的公共邻居节点,并计算未观测边得分r,将得分按降序排序,取前10,即为尚未存在的边中可能会首先产生连接的10条边。

    (5)评估精度(AUC),AUC值约为0.50。

    附代码:

    install.packages("igraph")

    library(igraph)

    library("Matrix")

    demo(package="igraph") #查看igraph子项目

    demo(package="igraph", community) #查看igraph子项目中community示例

    facebook<-read.table("/Users/zhangyuhao/Desktop/facebook.txt",header = T)

    g <- graph.data.frame(facebook)#加载数据框

    head(facebook)#看数据表的前6行

    tail(facebook)#看数据表的后6行

    data1 = as.matrix(facebook)

    g1<-graph.data.frame(as.matrix(facebook))

    g2<-get.adjacency(g1,sparse=FALSE) ###转换为邻接矩阵

    ###建立社交网络图

    jpeg(filename='facebook.jpg',width=2000,height=2000,units='px')#生成图片,大小是2000*2000px

    plot(g,

        vertex.size=2, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=0.5, #节点字体大小

        vertex.label.color='black', #节点字体颜色

        edge.arrow.size=0) #连线的箭头的大小

    #关闭图形设备,将缓冲区中的数据写入文件

    dev.off()

    ####关系图中某人或某几个人的关系图

    #某个人的关系图:

    jpeg(filename='mem1_1.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=1)

    plot(gn[[1]],

        vertex.size=5, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=2, #节点字体大小

        vertex.label.color='black', #节点字体颜色

        )

    dev.off()

    jpeg(filename='mem1_2.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=1)

    plot(gn[[2]],

        vertex.size=5, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=2, #节点字体大小

        vertex.label.color='black', #节点字体颜色

    )

    dev.off()

    jpeg(filename='mem1_100.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=1)

    plot(gn[[100]],

        vertex.size=5, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=1, #节点字体大小

        vertex.label.color='black', #节点字体颜色

    )

    dev.off()

    jpeg(filename='mem1_4039.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=1)

    plot(gn[[4039]],

        vertex.size=5, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=2, #节点字体大小

        vertex.label.color='black', #节点字体颜色

    )

    dev.off()

    #某个人的两层关系图:

    jpeg(filename='mem2_2.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=2)

    plot(gn[[2]],

        vertex.size=5, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=2, #节点字体大小

        vertex.label.color='black', #节点字体颜色

        vertex.label.color ='pink',

    )

    dev.off()

    #某个人的两层关系图:

    jpeg(filename='mem2_10.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=2)

    plot(gn[[10]],

        vertex.size=5, #节点大小

        layout=layout.fruchterman.reingold, #布局方式

        vertex.shape='circle', #带边框

        vertex.label.cex=2, #节点字体大小

        vertex.label.color='black', #节点字体颜色

        )

    dev.off()

    #某两个人的关系图:

    jpeg(filename='mem4.jpg',width=2000,height=2000,units='px')

    gn<-graph.neighborhood(g, order=1)

    plot(gn[[2]]+gn[[3]], layout=layout.fruchterman.reingold)

    dev.off()

    #根据联系人的多少决定节点的大小和色彩,连线设成弧线

    source("http://michael.hahsler.net/SMU/ScientificCompR/code/map.R")

    E(g)$curved <- 0.2 #将连线设成弧线,数值越大弧线越弯

    jpeg(filename='mem5.jpg',width=2000,height=2000,units='px')

    layout=layout.fruchterman.reingold

    plot(g,

      layout=layout,

        vertex.size=map(degree(g),c(1,20)),

        vertex.color=map(degree(g),c(1,20)))

    dev.off()

    #####统计特征分析

    ###网络基本属性

    V(g) #V(g)可以用来查看网络g的节点

    E(g) #E(g)可以用来查看网络g的边

    length(V(g)) #节点个数

    length(E(g)) #边条数

    is.igraph(g) #判断

    is.directed(g) #判断是否有向图

    graph.density(g) #网络密度

    dm <- diameter(g)#计算网路的直径,即MAX(任意两个节点之间的最短路径)

    dm

    average.path.length(g)#计算整个网路的平均距离(任意两节点直接的最短路径的平均值)

    clusters(g)$no#孤立点个数

    edge.connectivity(g)

    graph.adhesion(g)

    reciprocity(g)

    shortest.paths(g)#两点间的最短路径

    ###网络聚类系数

    transitivity(g,type = "global") #网络的聚类系数

    transitivity(g,type = "average") #网络的平均聚类系数

    transitivity(g,type = "local") #每个节点的聚类系数

    ###度分布

    degree<-degree(g,mode="all") #统计节点的度

    table(degree)

    degree.distribution(g)

    plot(degree.distribution(g), xlab="node degree")

    lines(degree.distribution(g))

    degree(g,mode="in") #mode=in点入度;out=点出度;total点度中心度,三者统称绝对点中心度

    degree(g,mode="out") #mode=in点入度;out=点出度;total点度中心度,三者统称绝对点中心度

    degree(g,normalized = T) #相对点中心度=绝对点中心度/最大度数(可以作为不同网络结构的比较,相对数与绝对数的区别)

    ###节点的重要性

    #- 拥有较高出/入度数的节点也拥有较高的“度中心性”

    #- 与其他节点之间有短路径的节点拥有较高的“密集中心性”

    #- 与其他节点对之间有最短路径的节点拥有较高的“中间性”

    #- 连接了许多中心性较高节点的节点拥有较高的“特征向量中心性”

    #- 本地簇系数意味着相邻节点的互联性

    degree(g) #点的中心度

    closeness(g)#接近中心度

    betweenness(g,normalized = T) #点的中间中心度

    edge.betweenness(g) #线的中间中心度

    evcent(g)$vector #特征向量中心度

    transitivity(g, type="local") #本地簇

    order(degree(g))[1:10]

    order(closeness(g))[1:10]

    order(betweenness(g))[1:10]

    order(evcent(g)$vector)[1:10]

    order(degree(g),decreasing = T)[1:10]

    order(closeness(g),decreasing = T)[1:10]

    order(betweenness(g),decreasing = T)[1:10]

    order(evcent(g)$vector,decreasing = T)[1:10]

    ###社区结构

    #1、设定社区的数目

    sg1 <- cluster_spinglass(g, spins=8, gamma=1.0) #spins是社区的数目

    jpeg(filename='dolphins_commu9.jpg',width=800,height=800,units='px')

    layout=layout.fruchterman.reingold

    plot(g, layout=layout, vertex.size=5, vertex.color= rainbow(10, .8, .8, alpha=.8)[sg1$membership],)

    dev.off()

    #画出某一社区,画出上面社区中,membership为1的社区。

    sg1 <- cluster_spinglass(g, spins=8, gamma=1.0)

    jpeg(filename='mem10.jpg',width=2000,height=2000,units='px')

    layout=layout.fruchterman.reingold

    subg <- induced.subgraph(g, which(membership(sg1)==1))

    plot(subg,

        layout=layout,

        vertex.size=5,

        vertex.color= 1,)

    dev.off()

    ###2、基于随机游走的社会划分

    com = walktrap.community(g, steps = 5)

    sg = data.frame(name = com$names, sg = com$membership + 1)

    subgroup = vector("list", length(unique(com$membership)))

    for(i in 1:length(unique(com$mem))){

    subgroup[[i]] = as.character(sg[sg[, 2]== i, 1])}

    rm(i)

    ## subgroup

    V(g)$sg = com$membership + 1

    V(g)$color = rainbow(max(V(g)$sg))[V(g)$sg]

    png("net_walktrap.jpg", width = 2000, height = 2000)

    par(mar = c(0, 0, 0, 0))

    set.seed(14)

    plot(g, layout = layout.fruchterman.reingold,

        vertex.size = 5,

        vertex.color = V(g)$color,

        vertex.label = NA,

        edge.color = grey(0.5),

        edge.arrow.mode = "-")

    dev.off()

    subgroup[[9]]

    subgroup[[2]]

    V(g)$bte = betweenness(g, directed = F)

    png("net_betweenness.png", width = 500, height = 500)

    par(mar = c(0, 2, 0, 0))

    plot(V(g)$bte)

    dev.off()

    #基于点连接的社群发现——clusters

    clusters(g,mode="strong")

    clusters(g,mode="weak")

    ###链接预测

    ###基于邻居的相似度指标——资源分配(RA)指标

    #划分训练集和测试集

    edge = matrix(0,nrow=88233,ncol=2,dimnames=list(c(1:88233),c("Source","Target")))

    k=1

    for(i in 1:length(data1[,1]))

    {

    for(j in i:length(data1[1,]))

    {

      if(facebook[i,j]==1)

    {

        edge[k,1]=i

        edge[k,2]=j

        k=k+1

    }

    }

    }#得到边数据

    v = length(data1[,1])

    e = length(edge[,1])

    set.seed(20181231)

    sp = sample(2, nrow(facebook), replace = TRUE, prob=c(0.8, 0.2))

    train_edge = as.data.frame(edge[sp == 1,])

    test_edge = as.data.frame(edge[sp == 2,])

    #转换为邻接矩阵形式

    train = matrix(0,nrow=1000,ncol=1000,dimnames=list(c(1:1000),c(1:1000)))

    test = matrix(0,nrow=1000,ncol=1000,dimnames=list(c(1:1000),c(1:1000)))

    for(i in 1:length(train_edge[,1]))

    {

    train[train_edge[i,1],train_edge[i,2]]=1

    }

    for(i in 1:length(test_edge[,1]))

    {

    test[test_edge[i,1],test_edge[i,2]]=1

    }

    g_train = graph.adjacency(train,mode="undirected",weighted=T)

    g_test = graph.adjacency(test,mode="undirected",weighted=T)

    #未观测边集

    train_edge = train_edge[order(train_edge[,1],train_edge[,2]),]

    max = (v*(v-1))/2

    row = max-length(train_edge[,1])

    edge_no = matrix(0,nrow=row,ncol=2,dimnames=list(c(1:row),c("Source","Target")))

    t=1

    s=1

    for(i in 1:v)

    {

    x = matrix(1:v,nrow=v,ncol=1)

    for(j in 1:v)

    {

      if(s<=length(train_edge[,1])&&train_edge[s,1]==i)

    {

        x[train_edge[s,2],1]=0

        s=s+1

    }

      else

        break

    }

    k=i+1

    while(k<=v)

    {

      if(x[k,1]!=0)

    {

        edge_no[t,1] = i

        edge_no[t,2] = x[k,1]

        t=t+1

    }

      k=k+1

    }

    }

    rm(x)

    #计算两点间的公共邻居结点及其度

    degree_train = degree(g_train)

    degree_train_each = as.data.frame(matrix(0,nrow=v,ncol=2,dimnames=list(c(1:v),c("Id","Degree"))))

    for(i in 1:v)

    {

    degree_train_each[i,1]=i

    degree_train_each[i,2]=degree_train[[i]]

    }#得到训练集每个节点的度

    #得到每个节点的邻居节点

    naber = as.data.frame(matrix(0,nrow=max(degree),ncol=v,dimnames=list(c(1:max(degree)),c(1:v))))

    for(i in 1:v)

    {

    k=1

    for(j in 1:v)

    {

      if(train[i,j]==1)

    {

        naber[k,i]=j

        k=k+1

    }

    }

    }

    #得到未观测边连接的两节点的公共邻居节点,并计算未观测边得分r

    r = as.data.frame(matrix(0,nrow=row,ncol=1))

    edge_no = cbind(edge_no,r)

    names(edge_no)=c("Source","Target","r")

    for(i in 1:length(edge_no[,1]))

    {

    x = edge_no[i,1]

    y = edge_no[i,2]

    r=0

    same = intersect(naber[,x],naber[,y])

    if(same[1]==0)

      edge_no[i,3]=r

    else

    {

      for(k in 1:length(same))

    {

        if(same[k]==0)

          break

        else

          if(degree_train_each[same[k],2]!=0)

            r=r+1/(degree_train_each[same[k],2])

    }

      edge_no[i,3]=r

    }

    }

    #排序

    edge_no = edge_no[order(edge_no[,1],edge_no[,2]),]

    Top10 = edge_no[order(edge_no[,3],decreasing=T),][1:10,]

    ####评估精度(AUC)

    #计算测试边集中的边的得分

    r = as.data.frame(matrix(0,nrow=length(test_edge[,1]),ncol=1))

    test_edge = cbind(test_edge,r)

    names(test_edge)=c("Source","Target","r")

    i=1

    j=1

    while(i<=length(test_edge[,1])&&j<=length(edge_no[,1]))

    {

    if(edge_no[j,1]>test_edge[i,1])

      i=i+1

    else

      if(edge_no[j,1]

        j=j+1

      else

        if(edge_no[j,2]>test_edge[i,2])

          i=i+1

        else

          if(edge_no[j,2]

            j=j+1

      else

          {

            test_edge[i,3]=edge_no[j,3]

            i=i+1

            j=j+1

          }

    }

    #计算未存在边集中的边的得分

    #构建未存在边集

    max = (v*(v-1))/2

    row1 = max-length(edge[,1])

    edge_not_exist = matrix(0,nrow=row1,ncol=2,dimnames=list(c(1:row1),c("Source","Target")))

    t=1

    s=1

    for(i in 1:v)

    {

    x = matrix(1:v,nrow=v,ncol=1)

    for(j in 1:v)

    {

      if(s<=e&&edge[s,1]==i)

    {

        x[edge[s,2],1]=0

        s=s+1

    }

      else

        break

    }

    k=i+1

    while(k<=v)

    {

      if(x[k,1]!=0)

    {

        edge_not_exist[t,1] = i

        edge_not_exist[t,2] = x[k,1]

        t=t+1

    }

      k=k+1

    }

    }

    rm(x)

    r = as.data.frame(matrix(0,nrow=length(edge_not_exist[,1]),ncol=1))

    edge_not_exist = cbind(edge_not_exist,r)

    names(edge_not_exist)=c("Source","Target","r")

    i=1

    j=1

    while(i<=length(edge_not_exist[,1])&&j<=length(edge_no[,1]))

    {

    if(edge_no[j,1]>edge_not_exist[i,1])

      i=i+1

    else

      if(edge_no[j,1]

        j=j+1

      else

        if(edge_no[j,2]>edge_not_exist[i,2])

          i=i+1

        else

          if(edge_no[j,2]

            j=j+1

          else

          {

            edge_not_exist[i,3]=edge_no[j,3]

            i=i+1

            j=j+1

          }

    }

    #比较测试边集和未存在边集,得AUC

    len1 = length(test_edge[,1])

    len2 = length(edge_not_exist[,1])

    down = len1*len2

    n1 = 0

    n0 = 0

    for(i in 1:length(test_edge[,1]))

    {

    for(j in 1:length(edge_not_exist[,1]))

    {

      if(test_edge[i,3]>edge_not_exist[j,3])

        n1=n1+1

      if(test_edge[i,3]==edge_not_exist[j,3])

        n0=n0+1

    }

    }

    AUC = (n1+0.5*n0)/down

    相关文章

      网友评论

          本文标题:facebook社交网络分析

          本文链接:https://www.haomeiwen.com/subject/elgzrqtx.html