Switch to unified view

a b/R/RandomWalkRestartMH_functions.R
1
# Credit to Valdeolivas et al.
2
# All the functions below come from the package RandomWalkRestartMH. 
3
# Due to build errors in Bioconducteur, and to avoid depreciation of the netOmics package, all functions imported by the package have been repatriated here.
4
5
# need ti keep:
6
# - RandomWalkRestartMH::create.multiplex
7
# - RandomWalkRestartMH::compute.adjacency.matrix
8
# - RandomWalkRestartMH::normalize.multiplex.adjacency
9
# - RandomWalkRestartMH::Random.Walk.Restart.Multiplex
10
11
#' @importFrom igraph set_vertex_attr
12
create.multiplex <- function(LayersList,...){
13
  
14
  if (!class(LayersList) == "list"){
15
    stop("The input object should be a list of graphs.")
16
  }
17
  
18
  
19
  Number_of_Layers <- length(LayersList)
20
  SeqLayers <- seq(Number_of_Layers)
21
  Layers_Name <- names(LayersList)
22
  
23
  # if (!all(sapply(SeqLayers, function(x) is.igraph(LayersList[[x]])))){
24
  #   stop("Not igraph objects")
25
  # }
26
  
27
  Layer_List <- lapply(SeqLayers, function (x) {
28
    if (is.null(V(LayersList[[x]])$name)){
29
      LayersList[[x]] <- 
30
        igraph::set_vertex_attr(LayersList[[x]],"name", 
31
                        value=seq(1,vcount(LayersList[[x]]),by=1))
32
    } else {
33
      LayersList[[x]]
34
    }
35
  })
36
  
37
  ## We simplify the layers 
38
  Layer_List <- 
39
    lapply(SeqLayers, function(x) simplify.layers(Layer_List[[x]]))
40
  
41
  ## We set the names of the layers. 
42
  
43
  if (is.null(Layers_Name)){
44
    names(Layer_List) <- paste0("Layer_", SeqLayers)
45
  } else {
46
    names(Layer_List) <- Layers_Name
47
  }
48
  
49
  ## We get a pool of nodes (Nodes in any of the layers.)
50
  Pool_of_Nodes <- 
51
    sort(unique(unlist(lapply(SeqLayers, 
52
                              function(x) V(Layer_List[[x]])$name))))
53
  
54
  Number_of_Nodes <- length(Pool_of_Nodes)
55
  
56
  Layer_List <-
57
    lapply(Layer_List, add.missing.nodes,Number_of_Layers,Pool_of_Nodes)
58
  
59
  # We set the attributes of the layer
60
  counter <- 0 
61
  Layer_List <- lapply(Layer_List, function(x) { 
62
    counter <<- counter + 1; 
63
    igraph::set_edge_attr(x,"type",igraph::E(x), value = names(Layer_List)[counter])
64
  })
65
  
66
  
67
  MultiplexObject <- c(Layer_List,list(Pool_of_Nodes=Pool_of_Nodes,
68
                                       Number_of_Nodes_Multiplex=Number_of_Nodes, 
69
                                       Number_of_Layers=Number_of_Layers))
70
  
71
  class(MultiplexObject) <- "Multiplex"
72
  
73
  return(MultiplexObject)
74
}
75
76
77
78
# internal 
79
#' @importFrom igraph as.undirected is_weighted E simplify
80
simplify.layers <- function(Input_Layer){
81
  
82
  ## Undirected Graphs
83
  Layer <- igraph::as.undirected(Input_Layer, mode = c("collapse"),
84
                         edge.attr.comb = igraph::igraph_opt("edge.attr.comb"))
85
  
86
  ## Unweighted or Weigthed Graphs
87
  if (igraph::is_weighted(Layer)){
88
    b <- 1
89
    weigths_layer <- igraph::E(Layer)$weight
90
    if (min(weigths_layer) != max(weigths_layer)){
91
      a <- min(weigths_layer)/max(weigths_layer)
92
      range01 <- (b-a)*(weigths_layer-min(weigths_layer))/
93
        (max(weigths_layer)-min(weigths_layer)) + a
94
      igraph::E(Layer)$weight <- range01
95
    } else {
96
      igraph::E(Layer)$weight <- rep(1, length(weigths_layer))
97
    }
98
  } else {
99
    igraph::E(Layer)$weight <- rep(1, ecount(Layer))
100
  }
101
  
102
  ## Simple Graphs
103
  Layer <- 
104
    igraph::simplify(Layer,remove.multiple = TRUE,remove.loops = TRUE, 
105
                     edge.attr.comb=mean)
106
  
107
  return(Layer)
108
}
109
110
#' @importFrom igraph add_vertices
111
add.missing.nodes <- function (Layers,Nr_Layers,NodeNames) {
112
  
113
  igraph::add_vertices(Layers,
114
               length(NodeNames[which(!NodeNames %in% igraph::V(Layers)$name)]),
115
               name=NodeNames[which(!NodeNames %in%  igraph::V(Layers)$name)])
116
}
117
118
119
#' @importFrom Matrix Diagonal bdiag
120
#' @importFrom igraph as_adjacency_matrix is_weighted
121
122
compute.adjacency.matrix <- function(x,delta = 0.5)
123
{
124
  if (!isMultiplex(x) & !isMultiplexHet(x)) {
125
    stop("Not a Multiplex or Multiplex Heterogeneous object")
126
  }
127
  if (delta > 1 || delta <= 0) {
128
    stop("Delta should be between 0 and 1")
129
  }
130
  
131
  N <- x$Number_of_Nodes_Multiplex
132
  L <- x$Number_of_Layers
133
  
134
  ## We impose delta=0 in the monoplex case.
135
  if (L==1){
136
    delta = 0
137
  }
138
  
139
  Layers_Names <- names(x)[seq(L)]
140
  
141
  ## IDEM_MATRIX.
142
  Idem_Matrix <- Matrix::Diagonal(N, x = 1)
143
  
144
  counter <- 0 
145
  Layers_List <- lapply(x[Layers_Names],function(x){
146
    
147
    counter <<- counter + 1;    
148
    if (igraph::is_weighted(x)){ 
149
      Adjacency_Layer <-  igraph::as_adjacency_matrix(x,sparse = TRUE, 
150
                                              attr = "weight")
151
    } else {
152
      Adjacency_Layer <-  igraph::as_adjacency_matrix(x,sparse = TRUE)
153
    }
154
    
155
    Adjacency_Layer <- Adjacency_Layer[order(rownames(Adjacency_Layer)),
156
                                       order(colnames(Adjacency_Layer))]
157
    colnames(Adjacency_Layer) <- 
158
      paste0(colnames(Adjacency_Layer),"_",counter)
159
    rownames(Adjacency_Layer) <- 
160
      paste0(rownames(Adjacency_Layer),"_",counter)
161
    Adjacency_Layer
162
  })
163
  
164
  MyColNames <- unlist(lapply(Layers_List, function (x) unlist(colnames(x))))
165
  MyRowNames <- unlist(lapply(Layers_List, function (x) unlist(rownames(x))))
166
  names(MyColNames) <- c()
167
  names(MyRowNames) <- c()
168
  SupraAdjacencyMatrix <- (1-delta)*(Matrix::bdiag(unlist(Layers_List)))
169
  colnames(SupraAdjacencyMatrix) <-MyColNames
170
  rownames(SupraAdjacencyMatrix) <-MyRowNames
171
  
172
  offdiag <- (delta/(L-1))*Idem_Matrix
173
  
174
  i <- seq_len(L)
175
  Position_ini_row <- 1 + (i-1)*N
176
  Position_end_row <- N + (i-1)*N
177
  j <- seq_len(L)
178
  Position_ini_col <- 1 + (j-1)*N
179
  Position_end_col <- N + (j-1)*N
180
  
181
  for (i in seq_len(L)){
182
    for (j in seq_len(L)){
183
      if (j != i){
184
        SupraAdjacencyMatrix[(Position_ini_row[i]:Position_end_row[i]),
185
                             (Position_ini_col[j]:Position_end_col[j])] <- offdiag
186
      }    
187
    }
188
  }
189
  
190
  SupraAdjacencyMatrix <- as(SupraAdjacencyMatrix, "dgCMatrix")
191
  return(SupraAdjacencyMatrix)
192
}
193
#' @importFrom Matrix t colSums
194
normalize.multiplex.adjacency <- function(x)
195
{
196
  if (!is(x,"dgCMatrix")){
197
    stop("Not a dgCMatrix object of Matrix package")
198
  }
199
  
200
  Adj_Matrix_Norm <- Matrix::t(Matrix::t(x)/(Matrix::colSums(x, na.rm = FALSE, dims = 1,
201
                                             sparseResult = FALSE)))
202
  
203
  return(Adj_Matrix_Norm)
204
}
205
206
Random.Walk.Restart.Multiplex <- function(x, MultiplexObject, Seeds, 
207
                                                  r=0.7,tau,MeanType="Geometric", DispResults="TopScores",...){
208
209
  
210
  L <- MultiplexObject$Number_of_Layers
211
  N <- MultiplexObject$Number_of_Nodes
212
  
213
  Seeds <- as.character(Seeds)
214
  if (length(Seeds) < 1 | length(Seeds) >= N){
215
    stop("The length of the vector containing the seed nodes is not 
216
         correct")
217
  } else {
218
    if (!all(Seeds %in% MultiplexObject$Pool_of_Nodes)){
219
      stop("Some of the seeds are not nodes of the network")
220
      
221
    }
222
  }
223
  
224
  if (r >= 1 || r <= 0) {
225
    stop("Restart partameter should be between 0 and 1")
226
  }
227
  
228
  if(missing(tau)){
229
    tau <- rep(1,L)/L
230
  } else {
231
    tau <- as.numeric(tau)
232
    if (sum(tau)/L != 1) {
233
      stop("The sum of the components of tau divided by the number of 
234
           layers should be 1")
235
    }
236
  }
237
  
238
  if(!(MeanType %in% c("Geometric","Arithmetic","Sum"))){
239
    stop("The type mean should be Geometric, Arithmetic or Sum")
240
  }
241
  
242
  if(!(DispResults %in% c("TopScores","Alphabetic"))){
243
    stop("The way to display RWRM results should be TopScores or
244
         Alphabetic")
245
  }
246
  
247
  ## We define the threshold and the number maximum of iterations for
248
  ## the random walker.
249
  Threeshold <- 1e-10
250
  NetworkSize <- ncol(x)
251
  
252
  ## We initialize the variables to control the flux in the RW algo.
253
  residue <- 1
254
  iter <- 1
255
  
256
  ## We compute the scores for the different seeds.
257
  Seeds_Score <- get.seed.scoresMultiplex(Seeds,L,tau)
258
  
259
  ## We define the prox_vector(The vector we will move after the first RWR
260
  ## iteration. We start from The seed. We have to take in account
261
  ## that the walker with restart in some of the Seed nodes, depending on
262
  ## the score we gave in that file).
263
  prox_vector <- matrix(0,nrow = NetworkSize,ncol=1)
264
  
265
  prox_vector[which(colnames(x) %in% Seeds_Score[,1])] <- (Seeds_Score[,2])
266
  
267
  prox_vector  <- prox_vector/sum(prox_vector)
268
  restart_vector <-  prox_vector
269
  
270
  while(residue >= Threeshold){
271
    
272
    old_prox_vector <- prox_vector
273
    prox_vector <- (1-r)*(x %*% prox_vector) + r*restart_vector
274
    residue <- sqrt(sum((prox_vector-old_prox_vector)^2))
275
    iter <- iter + 1;
276
  }
277
  
278
  NodeNames <- character(length = N)
279
  Score = numeric(length = N)
280
  
281
  rank_global <- data.frame(NodeNames = NodeNames, Score = Score)
282
  rank_global$NodeNames <- gsub("_1", "", row.names(prox_vector)[seq_len(N)])
283
  
284
  if (MeanType=="Geometric"){
285
    rank_global$Score <- geometric.mean(as.vector(prox_vector[,1]),L,N)    
286
  } else {
287
    if (MeanType=="Arithmetic") {
288
      rank_global$Score <- regular.mean(as.vector(prox_vector[,1]),L,N)    
289
    } else {
290
      rank_global$Score <- sumValues(as.vector(prox_vector[,1]),L,N)    
291
    }
292
  }
293
  
294
  if (DispResults=="TopScores"){
295
    ## We sort the nodes according to their score.
296
    Global_results <- 
297
      rank_global[with(rank_global, order(-Score, NodeNames)), ]
298
    
299
    ### We remove the seed nodes from the Ranking and we write the results.
300
    Global_results <- 
301
      Global_results[which(!Global_results$NodeNames %in% Seeds),]
302
  } else {
303
    Global_results <- rank_global    
304
  }
305
  
306
  rownames(Global_results) <- c()
307
  
308
  RWRM_ranking <- list(RWRM_Results = Global_results,Seed_Nodes = Seeds)
309
  
310
  class(RWRM_ranking) <- "RWRM_Results"
311
  return(RWRM_ranking)
312
}
313
314
#' @method print RWRM_Results
315
#' @export
316
print.RWRM_Results <- function(x,...)
317
{
318
  cat("Top 10 ranked Nodes:\n")
319
  print(head(x$RWRM_Results,10))
320
  cat("\nSeed Nodes used:\n")
321
  print(x$Seed_Nodes)
322
}
323
324
get.seed.scoresMultiplex <- function(Seeds,Number_Layers,tau) {
325
  
326
  Nr_Seeds <- length(Seeds)
327
  
328
  Seeds_Seeds_Scores <- rep(tau/Nr_Seeds,Nr_Seeds)
329
  Seed_Seeds_Layer_Labeled <- 
330
    paste0(rep(Seeds,Number_Layers),sep="_",rep(seq(Number_Layers), 
331
                                                length.out = Nr_Seeds*Number_Layers,each=Nr_Seeds))
332
  
333
  Seeds_Score <- data.frame(Seeds_ID = Seed_Seeds_Layer_Labeled,
334
                            Score = Seeds_Seeds_Scores, stringsAsFactors = FALSE)
335
  
336
  return(Seeds_Score)
337
}
338
339
340
geometric.mean <- function(Scores, L, N) {
341
  
342
  FinalScore <- numeric(length = N)
343
  
344
  for (i in seq_len(N)){
345
    FinalScore[i] <- prod(Scores[seq(from = i, to = N*L, by=N)])^(1/L)
346
  }
347
  
348
  return(FinalScore)
349
}
350
351
regular.mean <- function(Scores, L, N) {
352
  
353
  FinalScore <- numeric(length = N)
354
  
355
  for (i in seq_len(N)){
356
    FinalScore[i] <- mean(Scores[seq(from = i, to = N*L, by=N)])
357
  }
358
  
359
  return(FinalScore)
360
}
361
362
sumValues <- function(Scores, L, N) {
363
  
364
  FinalScore <- numeric(length = N)
365
  
366
  for (i in seq_len(N)){
367
    FinalScore[i] <- sum(Scores[seq(from = i, to = N*L, by=N)])
368
  }
369
  
370
  return(FinalScore)
371
}
372
373
isMultiplex <- function (x) 
374
{
375
  is(x, "Multiplex")
376
}
377
378
isMultiplexHet <- function (x) 
379
{
380
  is(x, "MultiplexHet")
381
}