{"word_count": 751, "character_count": 5705}
Ayant eu récemment à me pencher sur la question délicate des jointures entre réseaux ayant des liens en communs, j'en profite pour faire un point rapide sur les fonctions du package igraph permettant ces combinaisons. Si vous ne connaissez pas ce package, voyez les billets taggés R sur ce blog. Le script utilisé est téléchargeable sur github ici-même. et, pour les personnes qui n'ont pas envie et/ou besoin de s'inscrire sur ce git, il est reproduit à la fin de ce billet.Soit les deux graphes suivants :g1 et g2 sont deux graphes non orientés et ont trois sommets (ACD) et deux liens en commun (pléonasme...). Toutes les fonctions commentées ici prennent des graphes de même type en entrée (orientés ou non), certaines autorisent les combinaisons de graphes différents (un orienté et un non orienté).La première étape du script consiste à créer des attributs pour g1 et g2 : attributs du réseau, des sommets et des liens. L'objectif est de contrôler la perte éventuelle d'attributs lors des opérations effectuées. Pour mémoire, pour un graphe nommé g, la syntaxe de igraph est la suivante :g$densite &#60;- graph.density(g) #attribut du grapheV(g)$degre &#60;- degree(g) #attribut des sommets (V comme vertex)E(g)$betw &#60;- edge.betweenness(g) #attributs des liens (E comme edges)La fonction graph.complementer prend un graphe en attribut et crée son complémentaire : les liens absents dans le graphe de départ sont créés, les liens présents dans le graphe de départ sont supprimés. Un paramètre booléen loops permet de décider si on souhaite ou non générer des boucles (par défaut, loops = FALSE). Les attributs du réseau et des sommets sont conservés, les attributs des liens sont perdus (ce qui semble cohérent, ces liens étant supprimés).La fonction graph.difference prend deux graphes en entrée : seuls les liens présents dans le premier réseau et non dans le deuxième sont conservés, tous les attributs du premier réseau sont gardés. On peut également utiliser l'opérateur %m% (comme minus) : écrire graph.difference(g1,g2) ou g1%m%g2 est donc équivalent. La figure ci-dessous permet de comparer les résultats obtenus : le lien AD présent dans g1 et g2 donc les opérations g1-g2 et g2-g1 entraînent sa disparition.La fonction (non utilisée dans le script) graph.disjoint.union permet de joindre deux graphes dont les sommets sont distincts.La fonction graph.intersection (ou %s%) prend deux graphes en entrée et un paramètre keep.all.vertices (TRUE par défaut) permet de choisir entre garder l'ensemble des sommets et les seuls sommets connectés dans le graphe produit. Les attributs sont tous conservés. Enfin, la fonction graph.union prend deux graphes en entrée : tout lien présent dans un moins un graphesera dans le graphe produit - sans création de liens multiples - et tous les attributs seront conservés.Script completlibrary(igraph)#création des deux graphesd1 &#60;- rbind(c("A","B"),c("A","C"), c("B","C"), c("A","D"), c("D","E"))d2 &#60;- rbind(c("A","F"), c("A","D"), c("A","C"), c("C","I"))g1 &#60;- graph.data.frame(d1, directed = FALSE)g2 &#60;- graph.data.frame(d2, directed = FALSE)#visualisationpar(mfrow = c(1,2))plot(g1, main = "g1")plot(g2, main = "g2")dev.off()#3 points communs (ACD) et deux liens communs (AD et AC)#ajout d'attributs : degré des sommetsV(g1)$degree &#60;-&#160; degree(g1)V(g2)$degree &#60;- degree(g2)#ajout d'attributs aux liens (intermédiarité)E(g1)$between &#60;- edge.betweenness(g1)E(g2)$between &#60;- edge.betweenness(g2)#ajout d'attributs au réseau : densitég1$densite &#60;- graph.density(g1)g2$densite &#60;- graph.density(g2)#fonction graph.complementer#crée un graphe avec les liens absents du graphe de départ#les liens présents au départ sont eux suppriméscompg1 &#60;- graph.complementer(g1, loops = FALSE)plot(compg1)#les attributs des sommets et du graphe sont conservés#attributs des liens sont perdusV(compg1)$degreecompg1#fonction graph.difference premier réseau - deuxième réseau (opérateur %m%)#seuls les liens présents dans le premier réseau et non dans le deuxième sont conservés#tous les attributs du premier réseau sont gardésdiffg1 &#60;- graph.difference(g1, g2)diffg1diffg2 &#60;- graph.difference(g2, g1)#coordonnées (quasi) identiques pour faciliter la comparaisonlay &#60;- layout.fruchterman.reingold(g1)#lien A-D présent dans g1 et g2 donc g1-g2 et g2-g1 entrainent sa disparitionpar(mfrow = c(2,2))plot(g1, main = "g1", layout = lay, vertex.color = "red", vertex.size = 20, vertex.label.dist =3)plot(g2, main = "g2", layout = lay, vertex.color = "red", vertex.size = 20, vertex.label.dist =3)plot(diffg1, main = "graph.difference(g1, g2)", layout = lay, vertex.color = "red", vertex.size = 20, vertex.label.dist =3)plot(diffg2, main = "graph.difference(g2, g1)", layout = lay, vertex.color = "red", vertex.size = 20, vertex.label.dist =3)dev.off()#calculer degré actualiséV(diffg1)$degree2 &#60;- degree(diffg1)V(diffg1)$degreeV(diffg1)$degree2#graph.disjoint.union pour joindre des graphes dont les sommets différents (opérateur %du%)#liens communs à deux graphes : conserve les attributs#tous les sommets sont conservés (opérateur %s%)interg1 &#60;- graph.intersection(g1,g2, keep.all.vertices = TRUE)#seuls sommets adjacents aux liens communs sont gardés (ici ACD)interg2 &#60;- graph.intersection(g1,g2, keep.all.vertices = FALSE)par(mfrow = c(1,2))plot(interg1, sub = "graph.intersection(g1,g2,\nkeep.all.vertices = TRUE)")plot(interg2, sub = "graph.intersection(g1,g2,\nkeep.all.vertices = FALSE)")dev.off()#union de graphes : tout lien présent dans un moins un graphe#est dans le graphe produit - tous les attributs sont conservés#ne crée pas de liens multiplesuniong &#60;- graph.union(g1,g2) #opérateur %u%