6  Análisis de Redes Sociales

Describir las relaciones entre los elementos de una red y extraer conocimiento acerca de las estructuras sociales que existen en esa red. Tópico de enorme interés para extraer conocimiento de redes sociales en cualquier área.

en una red los actores no intervienen aislados

decribir todos los actores intervinientes en las redes

redes de alta complejidad

Existen muy destacadas aplicaciones para SNA:

6.1 R for SNA

Usaremos el paquete igraph. Nos servirá para analizar más adelante datos extraído de Twiter.

Ventajas de usar R:

  • Reproducible research no es posible con las aplicaciones GUI.

  • Herramientas sólidas para manipular los datos.

  • Cada vez más paquetes diseñados para hacer de R una herramienta completa de análisis de redes.

  • Paquetes statnet y igraph.

  • Thomas Lin Pedersen ha publicado los paquetes tidygraph y ggraph, que aprovechan la potencia de igraph de forma coherente con el flujo de trabajo de tidyverse.

  • Crear gráficos de red interactivos con el marco htmlwidgets que traduce el código de R a JavaScript.

6.1.1 Elementos de una red

  • nodos o vértices de grafo (nodes, vertices)
[1] "Tom Hanks"    "Gary Sinise"  "Bill Paxton"  "Kevin Bacon"  "Ed Harris"   
[6] "Sean Connery" "Robin Wright" "Nicolas Cage"
  • arcos o enlaces (edges, links)
      [,1]           [,2]          
 [1,] "Tom Hanks"    "Gary Sinise" 
 [2,] "Tom Hanks"    "Robin Wright"
 [3,] "Gary Sinise"  "Robin Wright"
 [4,] "Tom Hanks"    "Gary Sinise" 
 [5,] "Tom Hanks"    "Bill Paxton" 
 [6,] "Tom Hanks"    "Kevin Bacon" 
 [7,] "Tom Hanks"    "Ed Harris"   
 [8,] "Gary Sinise"  "Bill Paxton" 
 [9,] "Gary Sinise"  "Kevin Bacon" 
[10,] "Gary Sinise"  "Ed Harris"   
[11,] "Bill Paxton"  "Kevin Bacon" 
[12,] "Bill Paxton"  "Ed Harris"   
[13,] "Kevin Bacon"  "Ed Harris"   
[14,] "Ed Harris"    "Sean Connery"
[15,] "Ed Harris"    "Nicolas Cage"
[16,] "Sean Connery" "Nicolas Cage"

Nodos y arcos pueden contender atributos adicionales con importante información:

Warning: `graph.edgelist()` was deprecated in igraph 2.0.0.
ℹ Please use `graph_from_edgelist()` instead.
 [1] "Forest Gump" "Forest Gump" "Forest Gump" "Apollo 13"   "Apollo 13"  
 [6] "Apollo 13"   "Apollo 13"   "Apollo 13"   "Apollo 13"   "Apollo 13"  
[11] "Apollo 13"   "Apollo 13"   "Apollo 13"   "The Rock"    "The Rock"   
[16] "The Rock"   

6.1.2 Representación de redes

6.1.2.1 Grafos como listas de arcos

data.frame o matriz (si los datos del mismo tipo) que contiene dos columnas:

  • primera columna: nodos que son el origen de una conexión
  • segunda columna: nodos que son el destino de la conexión

Si el sentido es importante, la red se denomina dirigida, en otro caso, no dirigida.

alumnos1 <- c("Luis", "Ana", "Fran", "Pedro", "Laura", "Susana")
alumnos2 <- c("Juan", "Jose", "Amalia", "Lucía", "Maite", "Eduardo")

grupos <- data.frame(integrante1 = alumnos1, integrante2 = alumnos2, stringsAsFactors = F)

print(grupos)
  integrante1 integrante2
1        Luis        Juan
2         Ana        Jose
3        Fran      Amalia
4       Pedro       Lucía
5       Laura       Maite
6      Susana     Eduardo
str(grupos)
'data.frame':   6 obs. of  2 variables:
 $ integrante1: chr  "Luis" "Ana" "Fran" "Pedro" ...
 $ integrante2: chr  "Juan" "Jose" "Amalia" "Lucía" ...

6.1.2.2 Grafos como matrices

# Se pueden usar matrices 'sparse'
A <- rbind(c(0,1,0), c(1,0,1), c(1,0,0))
nodeNames <-  c("A","B","C")
dimnames(A) <-  list(nodeNames, nodeNames)
A
  A B C
A 0 1 0
B 1 0 1
C 1 0 0
str(A)
 num [1:3, 1:3] 0 1 1 1 0 0 0 1 0
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:3] "A" "B" "C"
  ..$ : chr [1:3] "A" "B" "C"

Caminos de longitud dos, tres, etc:

# Multiplicación matricial
A2 <- A %*% A
A2
  A B C
A 1 0 1
B 1 1 0
C 0 1 0
A3 <- A %*% A %*% A 
A3
  A B C
A 1 1 0
B 1 1 1
C 1 0 1

Representado arcos:

Arcos <- rbind(c("A","B"), c("B","A"), c("B","C"), c("C","A"))
Arcos
     [,1] [,2]
[1,] "A"  "B" 
[2,] "B"  "A" 
[3,] "B"  "C" 
[4,] "C"  "A" 

Usando tidverse:

library(tidyr)

Attaching package: 'tidyr'
The following object is masked from 'package:igraph':

    crossing
alumnos1 <- c("Luis", "Ana", "Fran", "Pedro", "Laura", "Susana")

alumnos2 <- c("Juan", "Jose", "Amalia", "Lucía", "Maite", "Eduardo")

node_list_alumnos <- tibble(id = unique(c(alumnos1,alumnos2)))

node_list_alumnos
# A tibble: 12 × 1
   id     
   <chr>  
 1 Luis   
 2 Ana    
 3 Fran   
 4 Pedro  
 5 Laura  
 6 Susana 
 7 Juan   
 8 Jose   
 9 Amalia 
10 Lucía  
11 Maite  
12 Eduardo
edge_list_alumnos <- tibble(from = alumnos1, to = alumnos2)

edge_list_alumnos
# A tibble: 6 × 2
  from   to     
  <chr>  <chr>  
1 Luis   Juan   
2 Ana    Jose   
3 Fran   Amalia 
4 Pedro  Lucía  
5 Laura  Maite  
6 Susana Eduardo

6.2 igraph

# Instalar la primera vez - descomentar
#install.packages("igraph")
#install.packages("igraphdata")
library(igraph)
library(igraphdata)


# Importar la red de datasets ya establecidos: igraphdata

# Limpia la memoria - Cuidado - borra todas las variables
rm(list=ls())

#Lista de datasets de redes de nodos en igraph
# data(package="igraphdata") 
 
# El paquete tiene un conjunto de datasets
# Carga data set y vemos que contiene 
#Red social entre miembros de club de karate de universidad 
data(karate,package="igraphdata") 
plot(karate)
This graph was created by an old(er) igraph version.
  Call upgrade_graph() on it to use with the current igraph version
  For now we convert it on the fly...

6.2.1 Acceder a elementos de grado

# UKfaculty: Friendship network of a UK university faculty
data(UKfaculty) 
plot(UKfaculty)
This graph was created by an old(er) igraph version.
  Call upgrade_graph() on it to use with the current igraph version
  For now we convert it on the fly...

UKfaculty
IGRAPH 6f42903 D-W- 81 817 -- 
+ attr: Type (g/c), Date (g/c), Citation (g/c), Author (g/c), Group
| (v/n), weight (e/n)
+ edges from 6f42903:
 [1] 57->52 76->42 12->69 43->34 28->47 58->51  7->29 40->71  5->37 48->55
[11]  6->58 21-> 8 28->69 43->21 67->58 65->42  5->67 52->75 37->64  4->36
[21] 12->49 19->46 37-> 9 74->36 62-> 1 15-> 2 72->49 46->62  2->29 40->12
[31] 22->29 71->69  4-> 3 37->69  5-> 6 77->13 23->49 52->35 20->14 62->70
[41] 34->35 76->72  7->42 37->42 51->80 38->45 62->64 36->53 62->77 17->61
[51]  7->68 46->29 44->53 18->58 12->16 72->42 52->32 58->21 38->17 15->51
[61] 22-> 7 22->69  5->13 29-> 2 77->12 37->35 18->46 10->71 22->47 20->19
+ ... omitted several edges
V(UKfaculty)
+ 81/81 vertices, from 6f42903:
 [1]  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] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
[51] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
[76] 76 77 78 79 80 81
E(UKfaculty)
+ 817/817 edges from 6f42903:
  [1] 57->52 76->42 12->69 43->34 28->47 58->51  7->29 40->71  5->37 48->55
 [11]  6->58 21-> 8 28->69 43->21 67->58 65->42  5->67 52->75 37->64  4->36
 [21] 12->49 19->46 37-> 9 74->36 62-> 1 15-> 2 72->49 46->62  2->29 40->12
 [31] 22->29 71->69  4-> 3 37->69  5-> 6 77->13 23->49 52->35 20->14 62->70
 [41] 34->35 76->72  7->42 37->42 51->80 38->45 62->64 36->53 62->77 17->61
 [51]  7->68 46->29 44->53 18->58 12->16 72->42 52->32 58->21 38->17 15->51
 [61] 22-> 7 22->69  5->13 29-> 2 77->12 37->35 18->46 10->71 22->47 20->19
 [71] 19->31 68->13 49->69 30->63  5->49 53->75 62->57 73->81 29->69 71->40
 [81] 19->58 49->42 37-> 5 18-> 2 20->80 75->53 15->54 76->58 40->23  5->12
 [91] 20->54  6->47 51->14 78-> 4 52->49 29->55 27->35 66-> 6 21->29  4->61
+ ... omitted several edges
V(UKfaculty)
+ 81/81 vertices, from 6f42903:
 [1]  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] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
[51] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
[76] 76 77 78 79 80 81
str(UKfaculty)
Class 'igraph'  hidden list of 10
 $ : num 81
 $ : logi TRUE
 $ : num [1:817] 56 75 11 42 27 57 6 39 4 47 ...
 $ : num [1:817] 51 41 68 33 46 50 28 70 36 54 ...
 $ : num [1:817] 580 411 719 376 569 215 533 620 527 592 ...
 $ : num [1:817] 241 433 238 352 258 274 115 24 263 25 ...
 $ : num [1:82] 0 6 23 27 37 65 74 91 93 101 ...
 $ : num [1:82] 0 9 28 32 40 50 58 76 82 87 ...
 $ :List of 4
  ..$ : num [1:3] 1 0 1
  ..$ :List of 4
  .. ..$ Type    : chr "TSPE"
  .. ..$ Date    : chr "Mon Mar 19 21:56:02 2007"
  .. ..$ Citation: chr "Nepusz T., Petroczi A., Negyessy L., Bazso F.: Fuzzy communities and the concept of bridgeness in complex netwo"| __truncated__
  .. ..$ Author  : chr "Nepusz T., Petroczi A., Negyessy L., Bazso F."
  ..$ :List of 1
  .. ..$ Group: num [1:81] 3 1 3 3 2 2 2 1 3 2 ...
  ..$ :List of 1
  .. ..$ weight: num [1:817] 4 14 4 4 10 2 6 2 4 4 ...
 $ :<environment: 0x10d2945c0> 
head(E(UKfaculty)$weight)
[1]  4 14  4  4 10  2
head(V(UKfaculty)$Group)
[1] 3 1 3 3 2 2

6.2.2 Construir/Modificar un grafo

Añadir arcos a un grafo vacío:

# Un grafo dirigido  vacío  
g <- make_empty_graph(n = 0, directed = TRUE)
g
IGRAPH 46cb55c D--- 0 0 -- 
+ edges from 46cb55c:
g <- g + vertices(c("A","B","C"))
g
IGRAPH a4d512a DN-- 3 0 -- 
+ attr: name (v/c)
+ edges from a4d512a (vertex names):
# Arcos:  A to C ,  B to C
g <- g + edges(c("A","C", "B","C")) 
g
IGRAPH 1f35f8b DN-- 3 2 -- 
+ attr: name (v/c)
+ edges from 1f35f8b (vertex names):
[1] A->C B->C
# Eliminar arco  A
g <- g - V(g)["A"]
g
IGRAPH 587042d DN-- 2 1 -- 
+ attr: name (v/c)
+ edge from 587042d (vertex names):
[1] B->C
# Eliminará todos los arcos conectados con A

Lista de arcos: graph() and get.edgelist():

# Un grafo dirigido  vacío  

#     graph() id desde   1. 
g1 <- graph( c(1,2, 1,3, 2,3, 3,4 ));g1
IGRAPH 8dd89bc D--- 4 4 -- 
+ edges from 8dd89bc:
[1] 1->2 1->3 2->3 3->4
summary(g1)
IGRAPH 8dd89bc D--- 4 4 -- 
plot(g1)

# El parámetro "directed" a  FALSE para
# grafos no dirigidos.  

g2 <- graph( c(1,2, 1,3, 2,3, 3,4 , 3, 5, 1, 3), directed=FALSE); g2 
IGRAPH 4bc3f24 U--- 5 6 -- 
+ edges from 4bc3f24:
[1] 1--2 1--3 2--3 3--4 3--5 1--3
summary(g2)
IGRAPH 4bc3f24 U--- 5 6 -- 
plot(g2)

#Obtener la lista de arcos a partir de un grafo   
edgelist<-get.edgelist(g2) ; edgelist
Warning: `get.edgelist()` was deprecated in igraph 2.0.0.
ℹ Please use `as_edgelist()` instead.
     [,1] [,2]
[1,]    1    2
[2,]    1    3
[3,]    2    3
[4,]    3    4
[5,]    3    5
[6,]    1    3
edgelist <- as_edgelist(g2) ; edgelist
     [,1] [,2]
[1,]    1    2
[2,]    1    3
[3,]    2    3
[4,]    3    4
[5,]    3    5
[6,]    1    3
# Obtener el grafo a partir de la lista de arcos
g3<-graph( t(edgelist));  g3;  plot(g3)
IGRAPH e29f9d2 D--- 5 6 -- 
+ edges from e29f9d2:
[1] 1->2 1->3 2->3 3->4 3->5 1->3

g3<-graph( edgelist);  g3;  plot(g3)
IGRAPH d0a7d53 D--- 5 6 -- 
+ edges from d0a7d53:
[1] 1->1 2->3 3->1 2->3 3->4 5->3

# algunos parámetros de plot 

plot(g3, 
     vertex.color="green", 
     edge.arrow.size=0.5, 
     vertex.size=25,
     edge.curved=0.5,
     layout_as_star=TRUE)

Matrices de adyacencia: graph.adjacency(), get.adjacency()

adjm_u<-matrix(
  c(0, 1, 0, 0, 1, 0,
  1, 0, 1, 0, 1, 0, 
  0, 1, 0, 1, 0, 0, 
  0, 0, 1, 0, 1, 1, 
  1, 1, 0, 1, 0, 0,
  0, 0, 0, 1, 0, 0),
  nrow=6, 
  ncol=6, 
  byrow = TRUE)
#grafo a partir de matriz de adyacencia
g_adj_u <- graph.adjacency(adjm_u, mode="undirected") 
Warning: `graph.adjacency()` was deprecated in igraph 2.0.0.
ℹ Please use `graph_from_adjacency_matrix()` instead.
plot(g_adj_u)
# Matriz de adyacencia a partir de grafo
A <- get.adjacency(g_adj_u); A
Warning: `get.adjacency()` was deprecated in igraph 2.0.0.
ℹ Please use `as_adjacency_matrix()` instead.

6 x 6 sparse Matrix of class "dgCMatrix"
                
[1,] . 1 . . 1 .
[2,] 1 . 1 . 1 .
[3,] . 1 . 1 . .
[4,] . . 1 . 1 1
[5,] 1 1 . 1 . .
[6,] . . . 1 . .
A <- as_adjacency_matrix(g_adj_u, sparse = FALSE)
A
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    0    1    0    0    1    0
[2,]    1    0    1    0    1    0
[3,]    0    1    0    1    0    0
[4,]    0    0    1    0    1    1
[5,]    1    1    0    1    0    0
[6,]    0    0    0    1    0    0

Grafo a partir de data frame

# Primero, crear el data frame
node1 = c("Ella", "Tu", "El"); node2 = c("El", "Ella", "Tu")
weight = c(10, -2, 3)
df = data.frame(node1, node2, weight); df
  node1 node2 weight
1  Ella    El     10
2    Tu  Ella     -2
3    El    Tu      3
# Crear el grafo 
g <- graph.data.frame(df, directed=FALSE); g
Warning: `graph.data.frame()` was deprecated in igraph 2.0.0.
ℹ Please use `graph_from_data_frame()` instead.
IGRAPH e5aee7e UNW- 3 3 -- 
+ attr: name (v/c), weight (e/n)
+ edges from e5aee7e (vertex names):
[1] Ella--El Ella--Tu Tu  --El
plot(g)
Warning in v(graph): Non-positive edge weight found, ignoring all weights
during graph layout.

# Si se conocen los vértices
# g <- graph.data.frame(df, vertices=listvertices, directed=FALSE);g

# Obtener los nombres de los nodos
V(g)$name 
[1] "Ella" "Tu"   "El"  
# Obtener los pesos de los arcos
E(g)$weight  
[1] 10 -2  3

Grafo a partir de literales

#?graph_from_literal

g <- graph_from_literal(A--C, A-+D, C-+A, , D-+C)
g
IGRAPH 057dd89 DN-- 4 3 -- 
+ attr: name (v/c)
+ edges from 057dd89 (vertex names):
[1] A->D C->A D->C
plot(g)

#IGRAPH DN-- 4 4 -- 
#+ attr: name (v/c)
#+ edges (vertex names):
#[1] A->D D->C D->B B->A

 G3 <-graph_from_literal(A-B, B -+C)
 plot(G3)

 G3 <-graph_from_literal(A-B, B -C)
 plot(G3)

grafo aleatorio

g_random <- sample_gnp(10, 0.2, directed = FALSE, loops = FALSE)
plot(g_random)

6.2.3 Visualización

Buscar ayuda de los comandos plot.igraph, igraph.plotting.

A continuación dibujamos algunos grafos interesantes:

#library(igraph)
# Trees
g <- make_tree(27, children=3)
g; plot(g)
IGRAPH d7a4a52 D--- 27 26 -- Tree
+ attr: name (g/c), children (g/n), mode (g/c)
+ edges from d7a4a52:
 [1] 1-> 2 1-> 3 1-> 4 2-> 5 2-> 6 2-> 7 3-> 8 3-> 9 3->10 4->11 4->12 4->13
[13] 5->14 5->15 5->16 6->17 6->18 6->19 7->20 7->21 7->22 8->23 8->24 8->25
[25] 9->26 9->27

# Cliques 
g <- make_full_graph(n=6)
g; plot(g)
IGRAPH bcbb405 U--- 6 15 -- Full graph
+ attr: name (g/c), loops (g/l)
+ edges from bcbb405:
 [1] 1--2 1--3 1--4 1--5 1--6 2--3 2--4 2--5 2--6 3--4 3--5 3--6 4--5 4--6 5--6

# Lattices
g <- make_lattice(dimvector = c(5,5), circular = FALSE)
V(g)$label <- NA
g; plot(g)
IGRAPH 3088078 U--- 25 40 -- Lattice graph
+ attr: name (g/c), dimvector (g/n), nei (g/n), mutual (g/l), circular
| (g/l), label (v/l)
+ edges from 3088078:
 [1]  1-- 2  1-- 6  2-- 3  2-- 7  3-- 4  3-- 8  4-- 5  4-- 9  5--10  6-- 7
[11]  6--11  7-- 8  7--12  8-- 9  8--13  9--10  9--14 10--15 11--12 11--16
[21] 12--13 12--17 13--14 13--18 14--15 14--19 15--20 16--17 16--21 17--18
[31] 17--22 18--19 18--23 19--20 19--24 20--25 21--22 22--23 23--24 24--25

#Stars
g <- make_star(n=10,mode = "undirected")
g;  plot(g)
IGRAPH 28977ee U--- 10 9 -- Star
+ attr: name (g/c), mode (g/c), center (g/n)
+ edges from 28977ee:
[1] 1-- 2 1-- 3 1-- 4 1-- 5 1-- 6 1-- 7 1-- 8 1-- 9 1--10

Anillo con conexiones cruzadas:

g <- make_ring(10, directed=TRUE, mutual=TRUE)

V(g)$name <- LETTERS[1:10]

g <-  g + edges(9,5, 7,1, 1,5)

plot(g)

6.2.4 Layout

Un layout es un conjunto de coordenadas x,y preestablecidas. Se pueden especificar manualmente o usando layout_functions

Determina la posición de los nodos en la red. Hay layouts ya diseñados o puedes diseñarlo desde 0.

Intentar minimizar cruces de arcos.

Algoritmos que lo consiguen: por ejemplo - Kamada Kawai algorithm, the Fruchterman Reingold algorithm, etc.

Lykamada <- layout.kamada.kawai(g)
plot(g, layout=Lykamada)

Lyfruchtermant <- layout.fruchterman.reingold(g)
plot(g, layout=Lyfruchtermant)

lo <- layout_in_circle(g)
head(lo, n=4) 
          [,1]      [,2]
[1,]  1.000000 0.0000000
[2,]  0.809017 0.5877853
[3,]  0.309017 0.9510565
[4,] -0.309017 0.9510565
# lo es una matriz de coordenadas  
lo
           [,1]          [,2]
 [1,]  1.000000  0.000000e+00
 [2,]  0.809017  5.877853e-01
 [3,]  0.309017  9.510565e-01
 [4,] -0.309017  9.510565e-01
 [5,] -0.809017  5.877853e-01
 [6,] -1.000000  1.224647e-16
 [7,] -0.809017 -5.877853e-01
 [8,] -0.309017 -9.510565e-01
 [9,]  0.309017 -9.510565e-01
[10,]  0.809017 -5.877853e-01
plot(g, layout=lo)

# See ?layout_ for a full list

# Para redes tipo árbol:  layout_as_tree
gTree <- make_tree(15)
plot(gTree, layout=layout_as_tree(gTree, root = 1))

# layout como un grid
plot(g, layout=layout_on_grid(g))

Mallas:

library(igraph)
#Buscar en ayuda
#?igraph::layout  
g <- make_tree(15)
set.seed(3952)
layout1 <- layout.fruchterman.reingold(g)
plot(g, layout=layout1)

# Otra malla diferente
plot(g, layout=layout.kamada.kawai)

# Malla interactiva - Ejecutar en consola
# tkplot(g, layout=layout.kamada.kawai)

6.2.5 Dibujar grafos ponderados

V(g)$label.cex <- ...
V(g)$label.color <- ...
V(g)$frame.color <- ... 
E(g)$color <- rgb(....
E(g)$width <-    

6.2.6 Cambiar aspecto y propiedades de un grafo

V(g)$shape 
V(g)$size
V(g)$color
  • vertex.shape
  • vertex.color
  • vertex.size
  • set_edge_attr
  • set_vertex_attr
  • set_graph_attr
plot(g, vertex.size = 20)

plot(g, vertex.size = 10, vertex.color = "blue", vertex.frame.color = NA, vertex.label = NA)

plot(g, vertex.size = 10, vertex.color = "blue", vertex.frame.color = NA, vertex.label.cex = .7,  vertex.label = NA, edge.curved = .5, edge.arrow.size = .3, edge.width = .7)

Note: colores en R http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ purrr     1.0.2
✔ forcats   1.0.0     ✔ readr     2.1.5
✔ ggplot2   3.5.1     ✔ stringr   1.5.1
✔ lubridate 1.9.3     ✔ tibble    3.2.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ lubridate::%--%()      masks igraph::%--%()
✖ dplyr::as_data_frame() masks tibble::as_data_frame(), igraph::as_data_frame()
✖ purrr::compose()       masks igraph::compose()
✖ tidyr::crossing()      masks igraph::crossing()
✖ dplyr::filter()        masks stats::filter()
✖ dplyr::lag()           masks stats::lag()
✖ purrr::simplify()      masks igraph::simplify()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
g1random <- sample_gnp(10, p=0.4)

V(g1random)[1]$color <- "yellow" 

g1random %>%
  set_edge_attr("color",value = "blue") %>%
 plot()

6.2.7 Ejemplos - plantillas

Plot vocales como rectángulos

g <- make_ring(10, directed=TRUE, mutual=TRUE)

V(g)$name <- LETTERS[1:10]

g <-  g + edges(9,5, 7,1, 1,5)

plot(g)

vowel <- V(g)$name %in% c("A","E","I","O","U") + 1 # gives 1 or 2
plot(g, layout=lo, vertex.shape=c("circle", "square")[vowel])

#colores
plot(g, layout=lo, vertex.color=c("tomato2", "royalblue")[vowel])

#tamaño
plot(g, layout=lo, vertex.size=c(15,30)[vowel])

#Propiedades usando atributos

V(g)$shape <- "circle" # Aplicado a todos los vértices
V(g)$size <- 15
V(g)$color <- "orange"
isVowel <- V(g)$name %in% c("A","E","I","O","U")
# Sobreescribir los nodos vocales 
V(g)[isVowel]$shape <- "square"
V(g)[isVowel]$color <- "royalblue"
V(g)[isVowel]$size <- 25

plot(g, layout=lo)

Propiedades de los arcos

E(g)$width <- 1
v1 <-V(g)[isVowel]
v1
+ 3/10 vertices, named, from b3a2f90:
[1] A E I
E(g)[v1  %--%  v1]$width <- 4

# Ver http://igraph.org/r/doc/igraph-es-indexing.html

plot(g, layout=lo)

#Arcos curvados
plot(g, layout=lo, edge.curved=0.3*which_mutual(g))

Agrupaciones por índices:

groupList <- list(vowelGroup = which(isVowel),
                  constGroup1 = c(2,3,4),
                  constGroup2 = c(6,7,8))

groupColours <- c(rgb(0,0.3,1,0.5),
                  rgb(0.8,0.4,0.1,0.5),
                  rgb(0.8,0.4,0.1,0.5))
plot(g, layout=layout_with_fr, # Fruchterman?Reingold layout
     mark.groups=groupList, # Mark the groups
     mark.col= groupColours,
     # Eliminar el borde
     mark.border = NA, 
     edge.curved=0.1*which_mutual(g))
text(0.45,0.1,"Vocales", cex=1.5)
text(0.5,0.9,"Grupo consonantes 1", cex=1.5)
text(-0.8,-1,"Grupo consonantes 2", cex=1.5)

6.3 Exportar grafos

igraph permite importar y exportar de/desde un considerable número de formatos. Se usan los comandos read_graph y write_graph. Un formato abierto (open) es graphml.

write_graph(g, "gr1.graphml", format="graphml")

Otros formatos:

  • edgelist: Fichero de texto con arcos en cada línea.

  • pajek: Pajek es un programa popular en Windows para análisis de redes.

  • gml: Graph Modelling Language es uno de los formatos abiertos más populares.

  • graphml: Graph Markup Language es un formato abierto basado en XML.

  • dot: Formato usado por GraphViz.

  • ** Gephi: Para exportar al formato nativo GEXF de Gephise usa el paquete rgexf al que puede convertirse desde un objeto igraph **

Referencias:

6.4 De Twitter

  • El primer paso será extraer los términos usando las técnicas de text mining y crear una matriz de términos (DTM - Document Term Matrix:).
  • Los documentos serían los tweets y los términos serían las palabras o grupos de palabras destacadas en los datos extraidos.
  • Objetivo: Construir una red de términos (personas) basada en sus co-ocurrencias en los mismos tweets (pertenencia a los mismos grupos).

6.5 Medidas de bondad, calidad

Analysis of the Networks to extract knowledge.

<http://snap.stanford.edu/class/cs224w-2015/slides/06-applicationsI.pdf%5D

Locate people in the network for…

  1. higher compensation

  2. positive performance evaluations

  3. more promotions

  4. more good ideas

Ego network is a special type of network consisting of one central node and all other nodes directly connected to it. The central node is known as ego, while the other surrounding nodes directly connected to it are known as alters.

<https://medium.com/applied-data-science/the-google-vs-trick-618c8fd5359f%5D

<http://olizardo.bol.ucla.edu/classes/soc-111/lessons-winter-2022/5-lesson-egonet-metrics.html%5D

Vamos a usar este grafo como ejemplo de las medidas de bondad del grafo.

library(igraph)
g1 <- graph( c(1, 2, 1, 3, 2,  3,
               3, 4, 3, 5, 1,  5,
               4, 2, 3, 6, 4,  8,
               8, 1, 9, 1, 10, 2,
               7, 6, 5,10))

g1
IGRAPH 0ac30aa D--- 10 14 -- 
+ edges from 0ac30aa:
 [1]  1-> 2  1-> 3  2-> 3  3-> 4  3-> 5  1-> 5  4-> 2  3-> 6  4-> 8  8-> 1
[11]  9-> 1 10-> 2  7-> 6  5->10
summary(g1)
IGRAPH 0ac30aa D--- 10 14 -- 
plot(g1)

Vértices, arcos

class(g1)
[1] "igraph"
V(g1)
+ 10/10 vertices, from 0ac30aa:
 [1]  1  2  3  4  5  6  7  8  9 10
V(g1)[1]
+ 1/10 vertex, from 0ac30aa:
[1] 1
E(g1)
+ 14/14 edges from 0ac30aa:
 [1]  1-> 2  1-> 3  2-> 3  3-> 4  3-> 5  1-> 5  4-> 2  3-> 6  4-> 8  8-> 1
[11]  9-> 1 10-> 2  7-> 6  5->10
E(g1)[1]
+ 1/14 edge from 0ac30aa:
[1] 1->2
class(V(g1))
[1] "igraph.vs"
class(E(g1))
[1] "igraph.es"

6.5.1 Centrality

Es una propiedad de la posicion del nodo en la red, de la importancia de los nodos en un grafo.

Contribución del nodo a la estructura de la red.

  • Un nodo puede ser importante por ejemplo, porque:

    • si lo eliminamos, la red podría desconectarse

    • gran número de arcos de entrada-salida

Redes con alta centralidad tienen pocos nodos con muchas conexiones.

Redes con baja centralidad tienen muchos nodos con similar o menos conexiones.

Hay diferentes medidas de centralidad.

Sociológicamente nodos centrales identifican líderes, de prestigio, con gran autonomía, que influencian a los que les siguen.

Ver https://en.wikipedia.org/wiki/Centrality#PageRank_centrality

6.5.2 Degree

Número de arcos conectados a un vértice. Señala la importancia de un vértice o el nivel de actividad del vértice en la red.

  • Cómo de central es un nodo en la red

  • Cuántos arcos de entrada-salida tiene o con cuántos nodos se conecta directamente via un arco.

centr_degree, igraph::degree

g1
IGRAPH 0ac30aa D--- 10 14 -- 
+ edges from 0ac30aa:
 [1]  1-> 2  1-> 3  2-> 3  3-> 4  3-> 5  1-> 5  4-> 2  3-> 6  4-> 8  8-> 1
[11]  9-> 1 10-> 2  7-> 6  5->10
plot(g1)

igraph::degree(g1)
 [1] 5 4 5 3 3 2 1 2 1 2
igraph::degree(g1, mode="in")
 [1] 2 3 2 1 2 2 0 1 0 1
igraph::degree(g1, mode="out")
 [1] 3 1 3 2 1 0 1 1 1 1
deg <- centr_degree(g1)

deg
$res
 [1] 5 4 5 3 3 2 1 2 1 2

$centralization
[1] 0.1358025

$theoretical_max
[1] 162

6.5.3 Betweenness

Mide el grado en el que la información fluye a través de un vértice particular y su importancia relativa como un intermediario en la red.

Un ejemplo claro, en una estrella el nodo central se encuentra en los caminos más cortos entre cualesquiera nodos de la red.

Describe el potencial de controlar flujos a través de la red. Nodos con alto “betweenness” tienen gran poder porque pueden parar los flujos de información.

Describe nodos que son conexiones clave o puentes entre grupos de nodos.

  • El número de caminos más cortos que pasan por un nodo dado (medida relativa) - la suma de las longitudes de los caminos más cortos entre otros nodos pasando por el nodo, dividida por las longitudes de camino más cortas (no necesariamente a través del nodo) entre los otros nodos.
igraph::betweenness(g1)
 [1] 14 14 25 11  6  0  0  6  0  6
  • Por el vértice 6 no pasa ningún *camino más corto* entre dos vértices.

  • Por el vértice 3 pasan 25 *caminos más cortos* entre dos vértices.

6.5.4 Edge_betweenness

Similar al anterior pero teniendo en cuenta cada arco.

g1 <- set.edge.attribute(g1, "weight", value= 1)
Warning: `set.edge.attribute()` was deprecated in igraph 2.0.0.
ℹ Please use `set_edge_attr()` instead.
bg <- edge_betweenness(g1)

plot(g1, edge.label = bg)

6.5.5 Closeness

Distancia a otros nodos. Un nodo con valor alto de este estimador es más central y puede difundir la información a muchos otros nodos.

  • Se obtiene como 1 divido por la suma de las distancias geodésicas desde un vértice al resto. Alcanzará su valor máximo cuando un vértice esté conectado a todos los demás. Longitud media de los caminos más cortos (geodésicos).

  • Mide cuantos pasos se requieren desde un vértice para alcanzar el resto de vértices de la red.

  • Caminos cortos entre vértices señalan que estos están cercanos unos a otros.

igraph::closeness(g1)
 [1] 0.08333333 0.05882353 0.08333333 0.06250000 0.04000000        NaN
 [7] 1.00000000 0.06250000 0.05000000 0.04761905

6.5.6 Eigenvector

No todas las conexiones tienen la misma importancia - medida de la importancia de un nodo.

  • La medida Eigenvector Centrality se calcula como el autovalor de mayor módulo de la matriz de adyacencia que contiene los pesos.

  • a high score to vertices that either have a lot of connections, or are connected to someone with a lot of connections

eigen_centrality(g1)
$vector
 [1] 0.94446858 0.87756472 1.00000000 0.67054129 0.68544140 0.31214483
 [7] 0.08943566 0.46273222 0.27060890 0.44783212

$value
[1] 3.490161

$options
$options$bmat
[1] "I"

$options$n
[1] 10

$options$which
[1] "LA"

$options$nev
[1] 1

$options$tol
[1] 0

$options$ncv
[1] 0

$options$ldv
[1] 0

$options$ishift
[1] 1

$options$maxiter
[1] 3000

$options$nb
[1] 1

$options$mode
[1] 1

$options$start
[1] 1

$options$sigma
[1] 0

$options$sigmai
[1] 0

$options$info
[1] 0

$options$iter
[1] 6

$options$nconv
[1] 1

$options$numop
[1] 20

$options$numopb
[1] 0

$options$numreo
[1] 15

6.5.7 Pagerank

Algoritmo de Google para realizar un ranking con la importancia de los resultados de la búsqueda.

Nodos son más importantes si tienen muchos enlaces de entrada.

page.rank(g1)
Warning: `page.rank()` was deprecated in igraph 2.0.0.
ℹ Please use `page_rank()` instead.
$vector
 [1] 0.09371203 0.18396681 0.20662720 0.08224805 0.10879979 0.10239617
 [7] 0.02370367 0.05865910 0.02370367 0.11618350

$value
[1] 1

$options
NULL

6.5.8 Diameter

El máximo camino más corto entre cualquier par de nodos. En grafos muy grandes indica la posibilidad de que la información se difunda más o menos fácilmente. El algoritmo tiene costo $O(n^3)$. En Twitter hay cientos de millones de usuarios,…

diameter - el camino más largo entre dos nodos.

plot(g1)

diameter(g1)
[1] 6

6.5.9 Caminos y distancias

Caminos de un vértice a otro o de grupos de vértices a otros.

Distancia geodésica: El menor número de arcos a atravesar para conectar dos nodos.

sp <- shortest_paths(g1, from="1", to="10")

sp$vpath
[[1]]
+ 3/10 vertices, from 0ac30aa:
[1]  1  5 10
sp1 <- shortest_paths(g1, from="1", to="9")
Warning in shortest_paths(g1, from = "1", to = "9"): At
vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
sp1$vpath
[[1]]
+ 0/10 vertices, from 0ac30aa:
distances(g1)
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    0    1    1    2    1    2    3    1    1     2
 [2,]    1    0    1    1    2    2    3    2    2     1
 [3,]    1    1    0    1    1    1    2    2    2     2
 [4,]    2    1    1    0    2    2    3    1    3     2
 [5,]    1    2    1    2    0    2    3    2    2     1
 [6,]    2    2    1    2    2    0    1    3    3     3
 [7,]    3    3    2    3    3    1    0    4    4     4
 [8,]    1    2    2    1    2    3    4    0    2     3
 [9,]    1    2    2    3    2    3    4    2    0     3
[10,]    2    1    2    2    1    3    4    3    3     0

Relacionado con distancias:

distance_table, mean_distance

6.5.10 Clustering

Whether your friends are likely to be friends.

Grupos: Subconjunto de vértices que comparten características en común.

  • Una primera forma es buscar los triángulos en el grafo. La medida de clustering (transitividad) es la frecuencia relativa de triángulos cerrados.

\[C=\\frac{3\*\\mbox{ número de triángulos }}{\\mbox{número de triples conectados}}\]

6.5.11 Transitivity

friends of friends to be friends and enemies of enemies to be enemies

Probabilidad de que vértices adyacentes de un vértice estén conectados - se denomina también coeficiente de agrupación o clustering.

transitivity, shortest_paths

6.5.11.1 Global clustering:

transitivity(g1, type = "global")
[1] 0.2571429

6.5.11.2 Local clustering

Fracción de triples conectados a través de cada vértice que son cerrados.

transitivity(g1, type = "local")
 [1] 0.2000000 0.3333333 0.3000000 0.3333333 0.3333333 0.0000000       NaN
 [8] 0.0000000       NaN 0.0000000

7 Otras medidas y definiciones

  • Densidad: Número de conexiones respecto al total de conexiones posibles. Un grafo completo tiene una densidad igual a 1 - edge_density.

  • Popularidad: nodos que son centrales tienden a ser más populares.

  • Cliques: todos con todos - clique_num(g, min=k) encuenta cliques con un mínimo de k vértices.

  • Componentes: Una componente es el conjunto de vértices de la que tienen conexiones entre ellos. Una red puede tener varias componentes - components

  • Nodos a distancia k - random_walk.

  • Hub, Authorities - hub_score, authority.score un nodo se denomina hub tiene muchos enlaces de salida y se denomina authorities si tiene muchos de entrada.

  • detección de comunidades: cluster_edge_betweenness