Le projet consiste à implémenter en R l’algorithme MCL de partitionnement de graphe (clustering) : à partir d’un graphe et d’un paramètre nommé inflate factor (noté IF par la suite), l’algorithme découpe le graphe en clusters. Exemple sur le graphe ci-dessous avec un IF de 3 :
Un graphe est un objet mathématique composé de sommets (vertex) reliés par des arètes (edge). Une des représentations informatiques consiste en une matrice carrée nommée matrice d’adjacence (adjacency matrix). Une cellule de cette matrice contient le poids de l’arète reliant deux sommets ou zéro en absence de lien.
Exemple :
A B C D
A 0 1 0 4
B 1 0 1 1
C 0 1 0 0
D 1 4 0 0
correspond au graphe :
Remarque : Dans ce dessin, l’épaisseur du trait de l’arète est proportionnel à son poids.
On distingue les graphes orientés (directed graph) des graphes non orientés (undirected graph). Dans un graphe orienté, les arètes sont appelées arcs et ont une direction (de A vers B). La matrice d’adjacence n’est donc plus obligatoirement symétrique et un choix arbitraire est fait concernant son interprétation : par exemple, les sommets sources correspondent aux lignes et les sommets destinations correspondent aux colonnes. Illustration :
A B C D A B C D
A 0 1 0 4 A 1 4
B 0 0 0 2 ou de manière plus lisible B 2
C 0 1 1 0 C 1 1
D 0 0 0 0 D
Remarque : Le lien de C vers lui-même s’appelle une boucle (loop).
Une bonne méthode de clustering maximise
En ce qui concerne le partitionnement de graphes, une bonne méthode vise à ce que les clusters obtenus
Pour identifier les clusters, MCL se base sur la remarque suivante : si on place un marcheur aléatoire sur un sommet d’un cluster, il a plus de chances (en se promenant aléatoirement d’un sommet à un autre) de rester dans le cluster (plus grande densité de liens) que d’en sortir.
Le procédé s’appuie donc sur le calcul des probabilités de marches aléatoires (probabilité de passer par un sommet et probabilité d’emprunter un arc) dans un graphe donné. Le calcul s’effectue sur des matrices de Markov qui représentent les probabilités de transition d’un sommet à un autre ; il s’agit donc d’une matrice d’adjacence dont la somme des lignes vaut 1 (la somme des probabilités de sortie d’un sommet vaut 1). Exemple avec le graphe précédent :
Matrice d'adjacence Matrice de Markov
A B C D A B C D
A 0 1 0 4 A 0 0.2 0 0.8
B 0 0 0 2 B 0 0 0 1
C 0 1 1 0 C 0 0.5 0.5 0
D 0 0 0 0 D 0 0 0 0
Remarque : Ces matrices sont également appelées matrices stochastiques ou encore matrices de transition.
L’algorithme MCL simule des marches aléatoires dans un graphe en alternant deux oprations appelées expansion et inflation. L’expansion correspond au calcul de marches aléatoires de grandes longueurs et coincide à élever une matrice stochastique à une certaine puissance. Concrètement, l’expansion consiste à multiplier la matrice avec elle-même avec le produit matriciel. L’inflation consiste à exagérer les probabilités de marches au sein d’un même cluster et à atténuer les probabilités de marches inter-clusters. En pratique, l’inflation consiste à élever chaque cellule de la matrice à une certaine puissance (inflate factor) puis à normaliser les valeurs obtenues afin que la matrice soit stochastique.
Au final, à force de répéter les opérations d’expansion et d’inflation sur la matrice de transition (et donc sur le graphe), celui-ci est décomposé en différentes composantes (composantes connexes) déconnectées les unes des autres et qui correspondent aux clusters. En d’autres termes, l’algorithme converge et la matrice n’évolue plus.
L’algorithme est donc le suivant :
M : matrice d’adjacence
ajouter les boucles à M
M_1 la matrice stochastique obtenue à partir de M
tant que on observe un changement dans la matrice
faire :
M_2 \(\leftarrow\) expansion(M_1)
M_2 \(\leftarrow\) inflation(M_2, inflate_factor)
déterminer s’il y a eu un changement
M_1 \(\leftarrow\) M_2
Le résultat est la matrice d’adjacence M_1 ou bien les composantes connexes du graphe correspondant à cette matrice.
Pour le chargement, le dessin et l’analyse des graphes, vous pourrez utiliser la librairie igraph.
Pour installer la librairie (si nécessaire) :
install.packages('igraph')
Puis pour l’utiliser :
library(igraph)
Pour créer un graphe à partir d’une matrice d’adjacence :
Exemple pour un graphe non orienté :
Matrice d'adjacence:
A B C D
A 0 1 0 4
B 1 0 1 1
C 0 1 0 0
D 1 4 0 0
Création de la matrice :
M = matrix(c(0,1,0,1, 1,0,1,4, 0,1,0,0, 4,1,0,0), ncol=4)
colnames(M) = rownames(M) = c('A', 'B', 'C', 'D')
M
## A B C D
## A 0 1 0 4
## B 1 0 1 1
## C 0 1 0 0
## D 1 4 0 0
Création du graphe à partir de la matrice
g=graph.adjacency(M, mode='undirected', weighted=TRUE)
La fonction V(g) permet d’accéder aux sommets (vertices) et la fonction E(g) aux arêtes (edges). On peut ainsi attribuer une étiquette aux sommets :
V(g)$label=c('A','B','C','D')
V(g)
## + 4/4 vertices, named, from 33cee8f:
## [1] A B C D
V(g)$label
## [1] "A" "B" "C" "D"
On peut accéder au poids des arêtes :
E(g)
## + 4/4 edges from 33cee8f (vertex names):
## [1] A--B A--D B--C B--D
E(g)$weight
## [1] 1 4 1 4
Remarque : il est possible de la même manière d’ajouter n’importe quel attribut sur les sommets ou les arêtes du graphe.
Et tracer le graphe :
plot(g, vertex.color='white', edge.width=E(g)$weight)
Pour un graphe orienté :
A B C D
A 0 1 0 4
B 0 0 0 2
C 0 1 1 0
D 0 0 0 0
Création de la matrice :
M = matrix(c(0,0,0,0, 1,0,1,0, 0,0,1,0, 4,2,0,0), ncol=4)
Création du graphe et ajout des étiquettes :
g=graph.adjacency(M, mode='directed', weighted=TRUE)
V(g)$label=c('A','B','C','D')
Dessin du graphe :
plot(g, vertex.color='white', edge.width=E(g)$weight)
Chargement du graphe fourni pour le projet : celui-ci est dans un format très simple appelé edgelist dans igraph. Sur chaque ligne du fichier, une arête est décrite par le sommet source et le sommet destination :
g = read.graph('http://silico.biotoul.fr/enseignement/m1/math/projet/toy.tgr', format='ncol', directed=FALSE)
Pour afficher le graphe :
plot(g)
Pour obtenir la matrice d’adjacence du graphe :
m = get.adjacency(g)
m
## 37 x 37 sparse Matrix of class "dgCMatrix"
## [[ suppressing 37 column names '0', '1', '2' ... ]]
##
## 0 . 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 . . . . . . . . . . . . . . . . . . .
## 1 1 . 1 1 1 1 1 1 . 1 1 1 1 1 1 1 1 1 1 1 . . . . . . . . . . . . . . . . .
## 2 1 1 . . 1 . . . . . . . . 1 . . 1 . 1 . 1 1 1 1 1 . . . . . . . . . . . .
## 3 1 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
## 4 1 1 1 . . . 1 1 1 1 1 1 1 1 1 1 1 1 . 1 . . . . . 1 . . . . . . . . . . .
## 5 1 1 . . . . 1 . . 1 1 . 1 1 1 1 . 1 . . . . . . . . . . . . . . . . . . .
## 6 1 1 . . 1 1 . . . 1 1 . 1 1 1 1 . 1 . . . . . . . . 1 . . . . . . . . . .
## 7 1 1 . . 1 . . . . . 1 . . 1 1 . 1 . . 1 . . . . . . . 1 1 1 1 1 1 . . . .
## 8 1 . . . 1 . . . . . 1 1 . . 1 . . . . . . . . . . . . . . . . . . . . . .
## 9 1 1 . . 1 1 1 . . . 1 . 1 1 1 1 . 1 . . . . . . . . 1 . . . . . . . . . .
## 10 1 1 . . 1 1 1 1 1 1 . 1 1 1 1 1 1 1 . 1 . . . . . 1 . . . . . . . 1 . . .
## 11 1 1 . . 1 . . . 1 . 1 . . 1 . . . . . . . . . . . . . . . . . . . . . . .
## 12 1 1 . . 1 1 1 . . 1 1 . . 1 1 1 . 1 . . . . . . . . 1 . . . . . . . . . .
## 13 1 1 1 . 1 1 1 1 . 1 1 1 1 . 1 1 1 1 . . . . . . . . . . . . . . . . . . .
## 14 1 1 . . 1 1 1 1 1 1 1 . 1 1 . 1 . 1 . 1 . . . . . . . . . . . . . 1 . . .
## 15 1 1 . . 1 1 1 . . 1 1 . 1 1 1 . . 1 . . . . . . . . . . . . . . . . . . .
## 16 1 1 1 . 1 . . 1 . . 1 . . 1 . . . . 1 . 1 1 . 1 1 . . . . . . . . . . . .
## 17 1 1 . . 1 1 1 . . 1 1 . 1 1 1 1 . . 1 . . . . . 1 . . . . . . . . . . . .
## 18 . 1 1 . . . . . . . . . . . . . 1 1 . . 1 1 1 1 1 . . . . . . . . . . . .
## 19 . 1 . . 1 . . 1 . . 1 . . . 1 . . . . . . . . . . . . 1 1 1 1 1 1 . . . .
## 20 . . 1 . . . . . . . . . . . . . 1 . 1 . . 1 1 1 1 . . . . . . . . . . . .
## 21 . . 1 . . . . . . . . . . . . . 1 . 1 . 1 . . . . . . . . . . . . . . . .
## 22 . . 1 . . . . . . . . . . . . . . . 1 . 1 . . 1 1 . . . . . . . . . . . 1
## 23 . . 1 . . . . . . . . . . . . . 1 . 1 . 1 . 1 . 1 . . . . . . . . . . . 1
## 24 . . 1 . . . . . . . . . . . . . 1 1 1 . 1 . 1 1 . . . . . . . . . . . . 1
## 25 . . . . 1 . . . . . 1 . . . . . . . . . . . . . . . . . . . . . . . . . .
## 26 . . . . . . 1 . . 1 . . 1 . . . . . . . . . . . . . . . . . . . . . . . .
## 27 . . . . . . . 1 . . . . . . . . . . . 1 . . . . . . . . 1 1 1 1 1 . . . .
## 28 . . . . . . . 1 . . . . . . . . . . . 1 . . . . . . . 1 . 1 1 1 1 . . . .
## 29 . . . . . . . 1 . . . . . . . . . . . 1 . . . . . . . 1 1 . 1 1 1 . . . .
## 30 . . . . . . . 1 . . . . . . . . . . . 1 . . . . . . . 1 1 1 . 1 1 . . . .
## 31 . . . . . . . 1 . . . . . . . . . . . 1 . . . . . . . 1 1 1 1 . 1 . . . .
## 32 . . . . . . . 1 . . . . . . . . . . . 1 . . . . . . . 1 1 1 1 1 . . . . .
## 33 . . . . . . . . . . 1 . . . 1 . . . . . . . . . . . . . . . . . . . 1 1 .
## 34 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 . 1 .
## 35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 . .
## 36 . . . . . . . . . . . . . . . . . . . . . . 1 1 1 . . . . . . . . . . . .
Vous allez donc implémenter MCL en R comme décrit plus haut. Pour cela, vous définirez plusieurs fonctions :
Pour la dernière fonction, vous aurez aussi besoin d’une fonction qui détecte s’il y a eu un changement. Pour cela, vous allez utilisez une fonction chaos qui calcule la valeur suivante :
La fonction renverra la plus forte valeur observée sur les lignes (le maximum des row_chaos obtenus sur chacune des lignes).
Remarque : Cette fonction chaos tient sur une ligne de code R.
Le pseudo-code la fonction MCL devient :
MCL(M, inflate=2) :
M2 = add_loops(M)
M2 = make_stochastic(M2)
change = 1
tant que change > 0.001 faire :
M2 = expansion(M2)
M2 = inflation(M2, inflate)
change = chaos(M2)
renvoyer arrondi(M2,3)
Ainsi, en appelant la fonction MCL comme suit :
g = read.graph('http://silico.biotoul.fr/enseignement/m1/math/projet/toy.tgr', format='ncol', directed=FALSE)
m = MCL(get.adjacency(g), inflate=3)
Création du graphe à partir de la matrice renvoyée par MCL
g2=graph.adjacency(m, mode='undirected', weighted=TRUE)
Le graphe obtenu est donc le suivant :
plot(g2)
La fonction clusters nous renvoie les composantes connexes du graphes (les clusters) :
clusters(g2)
## $membership
## 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
## 1 1 2 1 1 1 1 3 1 1 1 1 1 1 1 1 2 1 2 3 2 2 2 2 2 1 1 3 3 3 3 3 3 4 4 4 2
##
## $csize
## [1] 17 9 8 3
##
## $no
## [1] 4
Ainsi, clusters(g2)$membership est un vecteur qui à chaque sommet associe un numéro de cluster. Nous l’utilisons pour colorer les sommets du graphe de départ :
plot(g, vertex.color=clusters(g2)$membership)
Un compte rendu scientifique (habituel) sous la forme de fichier R-Markdown avec les fichiers .Rmd et .html ; il doit contenir notamment :
Questions à aborder :
Le compte rendu doit aussi comprendre une partie bilan avec par exemple :
Le tout est à envoyer par mail avant les fêtes de fin d’années.