Search code examples
rnetwork-programmingigraphmontecarlo

How to permute a network in igraph for R?


I'm trying to write a code for a Monte Carlo procedure in R. My goal is to estimate the significance of a metric calculated for a weighted, unipartite, undirected network formatted for the package igraph.

So far, I included the following steps in the code:

1. Create the weighted, unipartite, undirected network and calculate the observed Louvain modularity

nodes <- read.delim("nodes.txt")
links <- read.delim("links.txt")
anurosnet <- graph_from_data_frame(d=links, vertices=nodes, directed=F) 
anurosnet

modularity1 = cluster_louvain(anurosnet)
modularity1$modularity #observed value 

obs=modularity1$modularity
obs
real<-data.frame(obs)
real

2. Create the empty vector

Nperm = 9 #I am starting with a low n, but intend to use at least 1000 permutations
randomized.modularity=matrix(nrow=length(obs),ncol=Nperm+1)
row.names(randomized.modularity)=names(obs)
randomized.modularity[,1]=obs 
randomized.modularity

3. Permute the original network preserving its characteristics, calculate the Louvain modularity for all randomized networks, and compile the results in the vector

i<-1
while(i<=Nperm){ 

  randomnet <- rewire(anurosnet, with=each_edge(0.5)) #rewire vertices with constant probability
  E(randomnet)$weight <- sample(E(anurosnet)$weight) #shuffle initial weights and assign them randomly to edges

  mod<-(cluster_louvain(randomnet))

  mod$modularity

  linha = mod$modularity

  randomized.modularity[,i+1]=linha
  print(i)
  i=i+1
}
randomized.modularity #Here the result is not as expected

4. Plot the observed value against the distribution of randomized values

niveis<-row.names(randomized.modularity)
for(k in niveis)
{
  if(any(is.na(randomized.modularity[k,]) == TRUE))
  {
    print(c(k, "metrica tem NA"))
  } else {
    nome.arq<- paste("modularity",k,".png", sep="")
    png(filename= nome.arq, res= 300, height= 15, width=21, unit="cm")
    plot(density(randomized.modularity[k,]), main="Observed vs. randomized",)
    abline(v=obs[k], col="red", lwd=2, xlab="")
    dev.off()
    print(k)
    nome.arq<- paste("Patefield_Null_mean_sd_",k,".txt", sep="")
    write.table(cbind(mean(randomized.modularity[k,]),sd(randomized.modularity[k,])), file=paste(nome.arq,sep=""), 
                sep=" ",row.names=TRUE,col.names=FALSE)
  }
}

5. Estimate the P-value (significance)

significance=matrix(nrow=nrow(randomized.modularity),ncol=3)
row.names(significance)=row.names(randomized.modularity)
colnames(significance)=c("p (rand <= obs)", "p (rand >= obs)", "p (rand=obs)")

signif.sup=function(x) sum(x>=x[1])/length(x)
signif.inf=function(x) sum(x<=x[1])/length(x)
signif.two=function(x) ifelse(min(x)*2>1,1,min(x)*2)

significance[,1]=apply(randomized.modularity,1,signif.inf)
significance[,2]=apply(randomized.modularity,1,signif.sup)
significance[,3]=apply(significance[,-3],1,signif.two)

significance

Something is going wrong in step 3. I expected the vector to be filled with 10 values, but for some reason it stops after a while.

The slot "mod$modularity" suddenly receives 2 values instead of 1.

The two TXT files mentioned in the beginning of the code can be downloaded from here:

https://1drv.ms/t/s!AmcVKrxj94WClv8yQyqyl4IWk5mNvQ https://1drv.ms/t/s!AmcVKrxj94WClv8z_Pow5Tg2U7mjLw

Could you please help me?


Solution

  • Your error is due to a mismatch in dimensions with your randomized.modularity matrix and some of your randomized modularity results. In your example your matrix end up being [1 x Nperm] however sometimes 2 modularity scores are returned during the permutations. To fix this I simply store the results in a list. The rest of your analysis will need to be adjusted since you have a mismatch of modularity scores.

    library(igraph)
    
    nodes <- read.delim("nodes.txt")
    links <- read.delim("links.txt")
    anurosnet <- graph_from_data_frame(d=links, vertices=nodes, directed=F) 
    anurosnet
    
    modularity1 = cluster_louvain(anurosnet)
    modularity1$modularity #observed value 
    
    obs <- modularity1$modularity
    obs
    real<-data.frame(obs)
    real
    
    Nperm = 100 #I am starting with a low n, but intend to use at least 1000 permutations
    #randomized.modularity <- matrix(nrow=length(obs),ncol=Nperm+1)
    #row.names(randomized.modularity) <- names(obs)
    randomized.modularity <- list()
    randomized.modularity[1] <- obs 
    randomized.modularity
    
    
    for(i in 1:Nperm){ 
    
      randomnet <- rewire(anurosnet, with=each_edge(0.5)) #rewire vertices with constant probability
      E(randomnet)$weight <- sample(E(anurosnet)$weight) #shuffle initial weights and assign them randomly to edges
    
      mod <- (cluster_louvain(randomnet))      
      mod$modularity      
      linha = mod$modularity     
      randomized.modularity <- c(randomized.modularity, list(linha))
    
    }
    
    randomized.modularity
    

    Better way to write the loop

    randomized.modularity <- lapply(seq_len(Nperm), function(x){  
                                                randomnet <- rewire(anurosnet, with=each_edge(0.5)) #rewire vertices with constant probability
                                                E(randomnet)$weight <- sample(E(anurosnet)$weight) #shuffle initial weights and assign them randomly to edges
                                                return(cluster_louvain(randomnet)$modularity)
                                              })