I have an adjacency matrix (m) of 7000 nodes. Creating a network from this using
n <- 7000
m <- matrix(rbinom(3*n, 1, 0.2), n,n)
diag(m) <- 0
g <- network(m, directed = F)
is very slow. Is there a more efficient way of creating large random networks in R? Alternative methods such as using iGraph would also be appreciated.
With igraph, you can do:
library('igraph')
g <- graph.adjacency(m, mode='undirected')
The edges can then be retrieved using E(g) and vertices using V(g).
Check out the igraph docs for more information.
Related
I have a disconnected undirected network.
I want to identify and remove all the components that are cliques.
I do not want to remove all the cliques, just those that are themselves a component of the network.
How should I proceed?
library(igraph)
g <- graph_from_literal(a-b-c-d-b,e-f-g-e,h-i-l)
result <- graph_from_literal(a-b-c-d-b,h-i-l)
One solution is the following, but I do not know to what extent this is efficient in large networks.
d <- graph_from_literal(a-b-c-d-b,e-f-g-e,h-i-l)
d0 <- decompose.graph(d)
d1 <- disjoint_union(d0[unlist(lapply(d0, function(x) count_max_cliques(x)!=1))])
I am fairly new to igraph in R and to clustering/partitioning algorithms in general.
I have a general question on clusters. My idea is to build a contiguous cluster from a (directed) graph based on an attribute. What I try to achieve is something very similar to https://www.sixhat.net/finding-communities-in-networks-with-r-and-igraph.html. However, I am not sure I understand the functions (e.g. cluster_walktrap()) correctly. (I know there are some clustering methods that work on directed graphs, and some that don't.)
As an example: I use the network net from http://kateto.net/networks-r-igraph. Assuming I would like to end up with contiguous clusters based on the attribute audience.size (contrary to a clustering based on the betweeness), how would I use a clustering function from igraph?
cluster_walktrap(net, weights = E(net)$audience.size, steps = 4)?
How do I interpret the weight in this case?
MWE with data from: http://www.kateto.net/wordpress/wp-content/uploads/2016/01/netscix2016.zip
library(igraph)
nodes <- read.csv("Dataset1-Media-Example-NODES.csv", header=T, as.is=T)
links <- read.csv("Dataset1-Media-Example-EDGES.csv", header=T, as.is=T)
net <- graph_from_data_frame(d=links, vertices=nodes, directed=T)
net <- simplify(net, remove.multiple = F, remove.loops = T)
cluster_walktrap(net, weights = E(net)$audience.size, steps = 4)
Thank you very much!
Basically I have tried a few different ways of clustering. I can usually get to a point in iGraph where each node is labeled with a cluster. I can then identify all the nodes within a single cluster. However, this loses their edges.
I'd have to re-iterate back over the original dataset for all the nodes in cluster 1 to get only those where both nodes+the edge are within the cluster. I'd have to do this for every cluster.
This seems like a painfully long process and there is probably a shortcut my google-fu is missing.
So, is there an easy way to, after clustering or performing community detection processes, to maintain an individual cluster/community as its own smaller graph -- that is, retaining all nodes AND edges between them?
You can use delete.vertices() to create a subgraph. Example:
library(igraph)
set.seed(123)
# create random graph
g <- barabasi.game(100, directed = F)
plot(g, layout=layout.fruchterman.reingold)
# do community detection
wc <- multilevel.community(g)
V(g)$community <- membership(wc)
# make community 1 subgraph
g_sub <- delete.vertices(g, V(g)[community != 1])
plot(g_sub, layout=layout.fruchterman.reingold)
An alternative:
#Create random network
d <- sample_gnm(n=50,m=40)
#Identify the communities
dc <- cluster_walktrap(d)
#Induce a subgraph out of the first community
dc_1 <- induced.subgraph(d,dc[[1]])
#plot that specific community
plot(dc_1)
Trying to find communities in tweet data. The cosine similarity between different words forms the adjacency matrix. Then, I created graph out of that adjacency matrix. Visualization of the graph is the task here:
# 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)
I just want to have some more gap between separate clusters/communities.
To the best of my knowledge, you can't layout vertices of the same community close to each other, using igraph only. I have implemented this function in my package NetPathMiner. It seems it is a bit hard to install the package just for the visualization function. I will write the a simple version of it here and explain what it does.
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)
}
Basically, the function adds an extra vertex that is connected to all vertices belonging to the same community. The layout is calculated based on the new graph. Since each community is now connected by a common vertex, they tend to cluster together.
As Gabor said in the comment, increasing edge weights will also have similar effect. The function leverages this information, by increasing a cluster.strength, edges between created vertices and their communities are given higher weights.
If this is still not enough, you extend this principle (calculating the layout on a more connected graph) by adding edges between all vertices of the same communities (forming a clique). From my experience, this is a bit of an overkill.
I would like to generate a small world network with a fixed degree of 10.
I have tried watts.strogatz.game(1, 100, 5, 0) which results in a degree of 10 but only 5 neighbours for each node.
I'm guessing this is because the network is undirected. is there any way to make it undirected?
The igraph package contains many functions to create and manipulate graphs.
In particular, the get.edgelist function returns the list of edges, in the format you want.
The erdos.renyi.game function, when you set the probability to 1, generates complete graphs.
library(igraph)
g1 <- erdos.renyi.game(5, 1)
plot(g1)
get.edgelist(g1)
The degree.sequence.game function generates random graphs with a prescribed degree distribution.
g2 <- degree.sequence.game( c(3,3,3,2,1,1,1), method="vl" )
plot(g2)
The watts.strogatz.game function generates small-world networks.
g <- watts.strogatz.game(1, 100, 5, 0.05)
plot(g)