如何在R中使用igraph包绘制社区图并展开它?

10
尝试在推文数据中找到社区。不同单词之间的余弦相似度形成邻接矩阵。然后,我使用邻接矩阵创建了图形。这里的任务是可视化图形。
# Document Term Matrix
dtm = DocumentTermMatrix(tweets)

### adjust threshold here
dtms = removeSparseTerms(dtm, 0.998)
dim(dtms)

# cosine similarity matrix
t = as.matrix(dtms)

# comparing two word feature vectors
#cosine(t[,"yesterday"], t[,"yet"]) 

numWords = dim(t)[2]

# cosine measure between all column vectors of a matrix.
adjMat = cosine(t)

r = 3
for(i in 1:numWords)
{
  highElement  = sort(adjMat[i,], partial=numWords-r)[numWords-r]
  adjMat[i,][adjMat[i,] <  highElement] = 0
}

# build graph from the adjacency matrix
g = graph.adjacency(adjMat, weighted=TRUE, mode="undirected", diag=FALSE)
V(g)$name

# remove loop and multiple edges
g = simplify(g)
wt = walktrap.community(g, steps=5) # default steps=2
    table(membership(wt))

# set vertex color & size
nodecolor = rainbow(length(table(membership(wt))))[as.vector(membership(wt))]
nodesize = as.matrix(round((log2(10*membership(wt)))))
nodelayout = layout.fruchterman.reingold(g,niter=1000,area=vcount(g)^1.1,repulserad=vcount(g)^10.0, weights=NULL)

par(mai=c(0,0,1,0)) 
plot(g, 
     layout=nodelayout,
     vertex.size = nodesize,
     vertex.label=NA,
     vertex.color = nodecolor,
     edge.arrow.size=0.2,
     edge.color="grey",
     edge.width=1)

我希望将不同的簇/社区之间留出更多的间隔。

使用不同的颜色来展示不同的社区


你试过改变绘图的区域吗?默认是 area = vcount(graph)^2(http://www.inside-r.org/packages/cran/igraph/docs/layout) - Jon Cardoso-Silva
刚刚更新了最新的代码和图形可视化。 - magarwal
我不喜欢Fruchtermal.Reingold算法,因为这些问题经常发生,而且我通常不知道如何解决。我通常的做法是:将我的图形导出到Gephi中,使用Force Atlas 2算法(勾选选项“Prevent Overlap”和“Dissuade Hubs”),这样我通常可以得到一个良好的社区结构可视化。我希望有人能在这里告诉你解决这个问题的最佳方法,我也会学习它。 - Jon Cardoso-Silva
@jonathancardoso - 你怎么将R中的图导出到Gephi?Gephi看起来非常有趣! - magarwal
@magarwal,我通常使用igraph的write.graph(g,file="graph.gml",format="gml")命令来生成GML文件,然后将该文件加载到Gephi中。 - Jon Cardoso-Silva
显示剩余2条评论
1个回答

6
据我所知,仅使用igraph无法将同一社区的顶点布局在彼此附近。我已经在我的包NetPathMiner中实现了此功能。似乎为了可视化功能而安装该包有些困难。我将在此处编写其简化版本并解释其功能。
layout.by.attr <- function(graph, wc, cluster.strength=1,layout=layout.auto) {  
        g <- graph.edgelist(get.edgelist(graph)) # create a lightweight copy of graph w/o the attributes.
        E(g)$weight <- 1

        attr <- cbind(id=1:vcount(g), val=wc)
        g <- g + vertices(unique(attr[,2])) + igraph::edges(unlist(t(attr)), weight=cluster.strength)

        l <- layout(g, weights=E(g)$weight)[1:vcount(graph),]
        return(l)
}

基本上,该函数添加了一个额外的顶点,该顶点连接到所有属于同一社区的顶点。计算基于新图的布局。由于每个社区现在都由一个公共顶点连接,它们往往会聚集在一起。
正如Gabor在评论中所说,增加边缘权重也会产生类似的效果。该函数利用这些信息,通过增加cluster.strength,将创建的顶点和它们的社区之间的边缘赋予更高的权重。
如果这仍然不够,您可以通过在同一社区的所有顶点之间添加边缘(形成一个团)来扩展此原理(在更连通的图上计算布局)。根据我的经验,这有点过头了。

嘿,我遇到了一个错误:“Error in layout(g, weights = E(g)$weight)[1:(vcount(graph)), ] : subscript out of bounds”,有人遇到过这个问题吗? - Brofessor
此外,这行代码"g <- graph.edgelist(get.edgelist(graph)) # create a lightweight copy of graph w/o the attributes."的目的是创建一个完美的输入图形的副本吗?在此过程中丢失节点是否可以接受? - Brofessor
我怀疑你的图中存在未连接到任何其他节点的孤立节点,因此它们不会出现在仅由边创建的新图中。 我承认,我没有考虑到这种极端情况。 在你的情况下,你可以尝试直接复制图形 g <- graph - ahmohamed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接