En esta sección ilustremos cómo crear un grafo y cómo calcular las métricas de redes discutidas en la sección anterior. El documento guía de esta practica lo puede encontrar en: https://www.researchgate.net/publication/332652907_Breve_tutorial_para_visualizar_y_calcular_metricas_de_Redes_grafos_en_R_para_Economistas

Emplearemos el paquete igraph (Csardi y Nepusz, 2006) que permite hacer grafos y calcular una gran variedad de métricas relacionadas a estos. Adicionalmente, emplearemos el paquete readxl (Wickham y Bryan, 2018) que permite leer diferentes hojas de un archivo de Excel.

El primer paso corresponde a cargar la matriz de adyacencia:

library(igraph)
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
library(readxl)

grupo_jueves <- data.frame(read_excel("REDES GRUPO JUEVES.xlsx"))

graph_from_adjacency_matrix(grupo_jueves,
mode = c("directed", "undirected","max", "min", "upper", "lower", "plus"),
weighted = NULL, diag = TRUE, add.colnames = NULL, add.rownames = NA)
## Warning: The `adjmatrix` argument of `graph_from_adjacency_matrix()` must be a matrix as
## of igraph 1.6.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## IGRAPH 0764e56 D--- 1 1 -- 
## + edge from 0764e56:
## [1] 1->1
head(grupo_jueves)
##   ARANA.MONDRAGON ARBOLEDA.CASTILLO CAMACHO.CLARO CUARTAS.RAMIREZ
## 1               0                 1             1               1
## 2               0                 0             0               0
## 3               3                 1             0               0
## 4               0                 0             0               0
## 5              10                 1             1               1
## 6               0                 0             0               0
##   DELGADO.MORIBE FERRARIS.DAZA FLÓREZ.RECIO GUERRERO.DELGADO GUTIERREZ.GOMEZ
## 1             10             1            1                2               1
## 2              0             0            0                0               7
## 3              0             1           10                1               1
## 4              0             0            0                0               0
## 5              0             1            1                1               1
## 6              0             0            0                0               0
##   LUZ.KARIME.HERNANDEZ JIMENEZ.CARDONA LOZANO.RENGIFO NORIEGA.LUCUMI
## 1                    1               8              1              1
## 2                    6               0              7              0
## 3                    1               1              1              1
## 4                    3               0              0             10
## 5                    1               9              1              1
## 6                    0               0              0              0
##   OLMOS.POSSO PAREDES.MUÑOZ PASTRANA.OQUENDO PULIDO.LOPEZ QUIÑONEZ.CASTILLO
## 1           1             5                2            1                 1
## 2           7             0               NA            7                 0
## 3           1             2                1            1                 1
## 4           0             0               NA            0                 0
## 5           1             3                3            1                 3
## 6           0             0                2            0                 0
##   RESTREPO.ECHAVARRIA REYES.PIAMBA ROMO.CERON SANCHEZ.CACERES TRIANA.GONZALEZ
## 1                   1            1          1               1               1
## 2                   7            7          3               6               6
## 3                   1            1          1               1               1
## 4                   0            0          0               0               1
## 5                   1            1          1               1               1
## 6                   0            0          0               0               0
##   URBANO.VILLAMIL YANGUAS.OBANDO
## 1               1              1
## 2               7              6
## 3               1              1
## 4               0              0
## 5               1              1
## 6               0              0

Construcción del grafo

Ahora procedamos a la construcción del grafo. Como se mencionó anteriormente, el paquete que emplearemos para generar los grafos es igraph (Csardi y Nepusz, 2006). No obstante existen muchos paquetes que permiten construir grafos, este paquete crea grafos de una forma rápida y sencilla mediante la función graph.adjacency. Esta función tiene varios argumentos que permiten personalizar el grafo que se produzca.

Ahora, empleemos la información del objeto de clase data.frame que denominamos “grupo_jueves” para construir un grafo no dirigido sin que tenga en cuenta la información de la diagonal principal de la matriz de adyacencia y con los nombres de las columnas como nombres de los nodos empleando la función graph.adjacency. Dado que esta función tiene como argumento un objeto de clase matriz y no data.frame, será necesario primero transformar los datos. Adicionalmente, noten que el el objeto “grupo_jueves” actualmente tiene elementos “NA”. El primer paso entonces será remplazar los “NA” por ceros y después transformar el objeto a clase matriz. Después sí podemos proceder a construir el grafo no dirigido omitiendo la diagonal principal de la matriz de adyacencia y con los nombres de las columnas como nombres de los nodos. Esto se logra con las siguientes líneas de código:

grupo_jueves[is.na(grupo_jueves)] <- 0
grupo_jueves <- as.matrix(grupo_jueves)
class(grupo_jueves)
## [1] "matrix" "array"
head(grupo_jueves)
##      ARANA.MONDRAGON ARBOLEDA.CASTILLO CAMACHO.CLARO CUARTAS.RAMIREZ
## [1,]               0                 1             1               1
## [2,]               0                 0             0               0
## [3,]               3                 1             0               0
## [4,]               0                 0             0               0
## [5,]              10                 1             1               1
## [6,]               0                 0             0               0
##      DELGADO.MORIBE FERRARIS.DAZA FLÓREZ.RECIO GUERRERO.DELGADO GUTIERREZ.GOMEZ
## [1,]             10             1            1                2               1
## [2,]              0             0            0                0               7
## [3,]              0             1           10                1               1
## [4,]              0             0            0                0               0
## [5,]              0             1            1                1               1
## [6,]              0             0            0                0               0
##      LUZ.KARIME.HERNANDEZ JIMENEZ.CARDONA LOZANO.RENGIFO NORIEGA.LUCUMI
## [1,]                    1               8              1              1
## [2,]                    6               0              7              0
## [3,]                    1               1              1              1
## [4,]                    3               0              0             10
## [5,]                    1               9              1              1
## [6,]                    0               0              0              0
##      OLMOS.POSSO PAREDES.MUÑOZ PASTRANA.OQUENDO PULIDO.LOPEZ QUIÑONEZ.CASTILLO
## [1,]           1             5                2            1                 1
## [2,]           7             0                0            7                 0
## [3,]           1             2                1            1                 1
## [4,]           0             0                0            0                 0
## [5,]           1             3                3            1                 3
## [6,]           0             0                2            0                 0
##      RESTREPO.ECHAVARRIA REYES.PIAMBA ROMO.CERON SANCHEZ.CACERES
## [1,]                   1            1          1               1
## [2,]                   7            7          3               6
## [3,]                   1            1          1               1
## [4,]                   0            0          0               0
## [5,]                   1            1          1               1
## [6,]                   0            0          0               0
##      TRIANA.GONZALEZ URBANO.VILLAMIL YANGUAS.OBANDO
## [1,]               1               1              1
## [2,]               6               7              6
## [3,]               1               1              1
## [4,]               1               0              0
## [5,]               1               1              1
## [6,]               0               0              0

La última línea de código asignó un grafo con las características ya mencionadas al objeto “grupo_jueves.Und.graph” Este objeto tiene toda la información necesaria para trazar el grafo y otras estadísticas, pero, no lo muestra automáticamente. Para graficarlo se debe emplear la función plot de la siguiente manera:

grupo_jueves.Und.graph <- graph.adjacency(grupo_jueves, mode = "undirected", diag = FALSE)
## Warning: `graph.adjacency()` was deprecated in igraph 2.0.0.
## ℹ Please use `graph_from_adjacency_matrix()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
plot(grupo_jueves.Und.graph)

Finalmente, podemos hacer que los nodos sean de tamaño diferente para incluir alguna de las métricas discutidas anteriormente. Por ejemplo, supongamos que queremos hacer que el tamaño de los nodos en nuestro grafo dependa del puntaje de autoridad. En este caso la función authority.score(.)$vector permite crear un vector que contiene el puntaje de autoridad para cada jugador. Estos valores se utilizan para diferenciar el tamaño de los nodos empleando las siguientes líneas de código:

V(grupo_jueves.Und.graph)$color <- "yellow"
V(grupo_jueves.Und.graph)$shape <- "sphere"
E(grupo_jueves.Und.graph)$color <- "gray"

hs1 <- authority.score(grupo_jueves.Und.graph)$vector
## Warning: `authority.score()` was deprecated in igraph 2.0.0.
## ℹ Please use `hits_scores()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
plot(grupo_jueves.Und.graph, vertex.size=hs1*25)

La calidad de la visualización mejoró bastante. Si se quisiera un grafo dirigido se procedería de la siguiente manera:

grupo_jueves.Dir.graph <- graph.adjacency(grupo_jueves, mode = "directed", diag = FALSE)
V(grupo_jueves.Dir.graph)$color <- "yellow"
V(grupo_jueves.Dir.graph)$shape <- "sphere"
E(grupo_jueves.Dir.graph)$color <- "gray"
hs1 <- authority.score(grupo_jueves.Dir.graph)$vector
plot(grupo_jueves.Dir.graph, vertex.size=hs1*25, edge.arrow.size=0.8)

e introdujeron dos pequeños cambios respecto a la programación anterior. Primero, se cambia la opción mode de undirected a directed Segundo, en el argumento plot se introduce la opción edge.arrow.size, la cual controla el tamaño de las flechas del borde de cada arista. Esto último es necesario, dado que por defecto el tamaño de dichas flechas es lo suficientemente grande como para que la claridad del grafo sea nula, así que se debe ajustar a un tamaño adecuado.

Cálculo de las métricas de la Red

Medidas Locales

Centralidad

degree(grupo_jueves.Und.graph, mode="total")
##      ARANA.MONDRAGON    ARBOLEDA.CASTILLO        CAMACHO.CLARO 
##                   49                   84                   35 
##      CUARTAS.RAMIREZ       DELGADO.MORIBE        FERRARIS.DAZA 
##                   26                   48                   13 
##         FLÓREZ.RECIO     GUERRERO.DELGADO      GUTIERREZ.GOMEZ 
##                   33                   18                   91 
## LUZ.KARIME.HERNANDEZ      JIMENEZ.CARDONA       LOZANO.RENGIFO 
##                   85                   53                   77 
##       NORIEGA.LUCUMI          OLMOS.POSSO        PAREDES.MUÑOZ 
##                   24                   83                   34 
##     PASTRANA.OQUENDO         PULIDO.LOPEZ    QUIÑONEZ.CASTILLO 
##                   17                   84                   28 
##  RESTREPO.ECHAVARRIA         REYES.PIAMBA           ROMO.CERON 
##                   91                   89                   76 
##      SANCHEZ.CACERES      TRIANA.GONZALEZ      URBANO.VILLAMIL 
##                   82                   81                   80 
##       YANGUAS.OBANDO 
##                   83

Betweenness

betweenness(grupo_jueves.Und.graph)
##      ARANA.MONDRAGON    ARBOLEDA.CASTILLO        CAMACHO.CLARO 
##           3.12515228           0.07526882           1.74066005 
##      CUARTAS.RAMIREZ       DELGADO.MORIBE        FERRARIS.DAZA 
##           0.43633952           3.54935688           0.09302326 
##         FLÓREZ.RECIO     GUERRERO.DELGADO      GUTIERREZ.GOMEZ 
##           2.26931496           0.11360040          11.12684169 
## LUZ.KARIME.HERNANDEZ      JIMENEZ.CARDONA       LOZANO.RENGIFO 
##           5.36565299           8.61927718           0.08602151 
##       NORIEGA.LUCUMI          OLMOS.POSSO        PAREDES.MUÑOZ 
##           0.26315789           0.76158976           2.48252087 
##     PASTRANA.OQUENDO         PULIDO.LOPEZ    QUIÑONEZ.CASTILLO 
##           0.21637427           0.79342507           2.52732604 
##  RESTREPO.ECHAVARRIA         REYES.PIAMBA           ROMO.CERON 
##           0.81818299           0.06451613           5.00266330 
##      SANCHEZ.CACERES      TRIANA.GONZALEZ      URBANO.VILLAMIL 
##           0.06451613           3.57093386           2.83428416 
##       YANGUAS.OBANDO 
##           0.00000000

Medidas Globales

Closeness

closeness(grupo_jueves.Und.graph, mode = "all")
##      ARANA.MONDRAGON    ARBOLEDA.CASTILLO        CAMACHO.CLARO 
##           0.04166667           0.03448276           0.04000000 
##      CUARTAS.RAMIREZ       DELGADO.MORIBE        FERRARIS.DAZA 
##           0.02777778           0.04166667           0.02564103 
##         FLÓREZ.RECIO     GUERRERO.DELGADO      GUTIERREZ.GOMEZ 
##           0.04166667           0.03030303           0.04166667 
## LUZ.KARIME.HERNANDEZ      JIMENEZ.CARDONA       LOZANO.RENGIFO 
##           0.03703704           0.04166667           0.03448276 
##       NORIEGA.LUCUMI          OLMOS.POSSO        PAREDES.MUÑOZ 
##           0.02777778           0.03571429           0.03846154 
##     PASTRANA.OQUENDO         PULIDO.LOPEZ    QUIÑONEZ.CASTILLO 
##           0.02631579           0.03571429           0.04166667 
##  RESTREPO.ECHAVARRIA         REYES.PIAMBA           ROMO.CERON 
##           0.03571429           0.03448276           0.04000000 
##      SANCHEZ.CACERES      TRIANA.GONZALEZ      URBANO.VILLAMIL 
##           0.03448276           0.03846154           0.03703704 
##       YANGUAS.OBANDO 
##           0.03333333

Puntaje de Autoridad

authority.score(grupo_jueves.Und.graph)$vector
##      ARANA.MONDRAGON    ARBOLEDA.CASTILLO        CAMACHO.CLARO 
##           0.24864396           0.93656824           0.20802789 
##      CUARTAS.RAMIREZ       DELGADO.MORIBE        FERRARIS.DAZA 
##           0.10947063           0.24521533           0.04349606 
##         FLÓREZ.RECIO     GUERRERO.DELGADO      GUTIERREZ.GOMEZ 
##           0.20129908           0.11288523           0.95881727 
## LUZ.KARIME.HERNANDEZ      JIMENEZ.CARDONA       LOZANO.RENGIFO 
##           0.89561390           0.25443456           0.85793963 
##       NORIEGA.LUCUMI          OLMOS.POSSO        PAREDES.MUÑOZ 
##           0.08998908           0.91724165           0.19800033 
##     PASTRANA.OQUENDO         PULIDO.LOPEZ    QUIÑONEZ.CASTILLO 
##           0.07142421           0.92990321           0.18769753 
##  RESTREPO.ECHAVARRIA         REYES.PIAMBA           ROMO.CERON 
##           1.00000000           0.98743432           0.80770709 
##      SANCHEZ.CACERES      TRIANA.GONZALEZ      URBANO.VILLAMIL 
##           0.91227634           0.87118972           0.86955157 
##       YANGUAS.OBANDO 
##           0.92654841

Otras medidas para detectar nodos importantes

Distancia Promedio

mean_distance(grupo_jueves.Und.graph)
## [1] 1.186667

Excentricidad

eccentricity(grupo_jueves.Und.graph, mode = "all")
##      ARANA.MONDRAGON    ARBOLEDA.CASTILLO        CAMACHO.CLARO 
##                    1                    2                    2 
##      CUARTAS.RAMIREZ       DELGADO.MORIBE        FERRARIS.DAZA 
##                    2                    1                    2 
##         FLÓREZ.RECIO     GUERRERO.DELGADO      GUTIERREZ.GOMEZ 
##                    1                    2                    1 
## LUZ.KARIME.HERNANDEZ      JIMENEZ.CARDONA       LOZANO.RENGIFO 
##                    2                    1                    2 
##       NORIEGA.LUCUMI          OLMOS.POSSO        PAREDES.MUÑOZ 
##                    2                    2                    2 
##     PASTRANA.OQUENDO         PULIDO.LOPEZ    QUIÑONEZ.CASTILLO 
##                    2                    2                    1 
##  RESTREPO.ECHAVARRIA         REYES.PIAMBA           ROMO.CERON 
##                    2                    2                    2 
##      SANCHEZ.CACERES      TRIANA.GONZALEZ      URBANO.VILLAMIL 
##                    2                    2                    2 
##       YANGUAS.OBANDO 
##                    2

Medidas Agregadas para la Red

Diámetro

diameter(grupo_jueves.Und.graph)
## [1] 2

Densidad

grupo_jueves.1.0<-grupo_jueves
for (i in 1:ncol(grupo_jueves.1.0)){
for (j in 1:nrow(grupo_jueves.1.0)){
  grupo_jueves.1.0[j,i]<-ifelse(grupo_jueves.1.0[j,i]>0,1,grupo_jueves.1.0[j,i])
}
}
GrafDens <- graph.adjacency(grupo_jueves.1.0, mode = "undirected", weighted = NULL,
diag = FALSE, add.colnames=NULL)
edge_density(GrafDens)
## [1] 0.8133333

Transitividad

transitivity(grupo_jueves.Und.graph)
## [1] 0.882575

Reciprocidad

reciprocity(grupo_jueves.Und.graph)
## [1] 1

Más sobre grafos y otras visualizaciones

Grafo Ponderado

Anteriormente se discutió la diferencia de un grafo ponderado y uno no ponderado. Hasta el momento hemos construido grafos no ponderaros, a continuación, se muestra cómo construir un grafo ponderado. Recordemos que un grafo ponderado es aquel que conecta los nodos por una sola línea (independientemente del número de enlaces que existen entre ellos) y dicha línea tiene asociada una etiqueta o algo que de alguna manera revele el número de conexiones que unen ese par de nodos. Para construir este tipo de grafos, debemos partir de un grafo no dirigido que nos permita emplear alguna forma de ponderar las aristas. Por ejemplo:

grupo_jueves.Und.Pond.graph <- graph.adjacency(grupo_jueves, weighted = TRUE, mode = "undirected",
diag = FALSE)

plot(grupo_jueves.Und.Pond.graph, edge.width=E(grupo_jueves.Und.Pond.graph)$weight)

## Disposición del Grafo

La disposición de los nodos de un grafo responde a algoritmos que asignan las coordenadas de los nodos de una red. Y la verdad esto es arbitrario; es decir, no existe una forma adecuada de disponer los nodos, existen muchas maneras y el investigador deberá decidir cuál es la que permite visualizar mejor las características de la red.

El argumento layout de la función plot del paquete igraph permite emplear diferentes algoritmos. Continuando con el grafo ponderado no direccionado construido en la sección anterior, podemos, por ejemplo, organizar todos los nodos alrededor de un circulo empleando la siguiente línea de código:

plot(grupo_jueves.Und.Pond.graph, layout= layout_in_circle(grupo_jueves.Und.Pond.graph))

## Otra manera de representar la red - heatmap

library(reshape)
row.names(grupo_jueves) <- variable.names(grupo_jueves)
grupo_jueves.por.parejas <- melt(grupo_jueves)
## Warning in type.convert.default(X[[i]], ...): 'as.is' should be specified by
## the caller; using TRUE
## Warning in type.convert.default(X[[i]], ...): 'as.is' should be specified by
## the caller; using TRUE
head(grupo_jueves.por.parejas)
##                  X1              X2 value
## 1   ARANA.MONDRAGON ARANA.MONDRAGON     0
## 2 ARBOLEDA.CASTILLO ARANA.MONDRAGON     0
## 3     CAMACHO.CLARO ARANA.MONDRAGON     3
## 4   CUARTAS.RAMIREZ ARANA.MONDRAGON     0
## 5    DELGADO.MORIBE ARANA.MONDRAGON    10
## 6     FERRARIS.DAZA ARANA.MONDRAGON     0

Detección de Comunidades

library(ggplot2)
ggplot(data = grupo_jueves.por.parejas, aes(x= X2, y= X1, fill=value)) + geom_tile() +
geom_text(aes(X2, X1, label = value), color = "grey", size = 4) +
scale_fill_gradient(low = "white", high = "steelblue") +
xlab("receptor") + ylab("pasador") + labs(fill = "pases")

HC.grupo_jueves.Und.Pond.graph <- cluster_edge_betweenness(grupo_jueves.Und.Pond.graph)
## Warning in cluster_edge_betweenness(grupo_jueves.Und.Pond.graph): At
## vendor/cigraph/src/community/edge_betweenness.c:503 : Membership vector will be
## selected based on the highest modularity score.
dendPlot(HC.grupo_jueves.Und.Pond.graph, mode="hclust", rect = 2)
## Warning: `dendPlot()` was deprecated in igraph 2.0.0.
## ℹ Please use `plot_dendrogram()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

plot(HC.grupo_jueves.Und.Pond.graph, grupo_jueves.Und.Pond.graph)