El paquete igraph hace sencilla la visualización y exploración de redes, pero para hacer análisis inferenciales necesitamos otras herramientas como los paquetes asociados a statnet que tienen su propia forma de definir una red. Por fortuna, tenemos paquetes como intergraph que nos permiten transformar entre las estructuras requeridas por cada paquete de una forma sencilla.

library(statnet)
library(intergraph)
library(igraph)
library(ergm)

edgelist <- readRDS("dta/edgelist-diputados.RDS")
atributos <- readRDS("dta/atributos-diputados.RDS")

Supongamos que estamos interesados en analizar la red de colaboración de diputados pero que queremos estudiar los determinantes de la formación de aristas entre dos vértices. Por ejemplo, queremos estudiar si la formación de aristas está relacionada con, ya no solo el partido, si no con otros atributos de los diputados. Para eso, queremos estudiar el proceso de generación de datos de la red y estudiar la distribución muestral de los estadísticos de la red. Pero antes de nada, tenemos que incorporar nuestra base de datos de atributos a nuestra lista de vértices, y transformar una red de igraph en una de statnet.

Empecemos creando una base de datos con atributos usando graph_from_data_frame del paquete igraph, que nos permite definir una red con atributos a nivel de vértice usando columnas de una base de datos.

edgelist <- as.data.frame(edgelist)
names(edgelist) <- c("from", "to")
edgelist$from <- as.character(edgelist$from)
edgelist$to <- as.character(edgelist$to)
atributos$id <- as.character(atributos$id)

Ahora podemos definir la red con atributos usando el argumento vertices que toma una base de datos en la que los nombres de la fila se usan para hacer el emparejamiento con los vértices de la lista de aristas.

g <- graph_from_data_frame(edgelist, directed=FALSE, vertices=atributos)

¿Por qué ha fallado esta operación?

length(unique(atributos$id))
length(unique(unlist(edgelist)))

Como vemos, la base de datos de atributos define más diputados que los que están presentes en la lista de aristas. Eso no es un problema. Sin embargo, también vemos que

mis <- setdiff(unlist(edgelist), atributos$id) ## Diputados que ya no estan
mis

Debemos por tanto ajustar las dos bases de datos quitando de la lista de aristas las que se refieren a diputados que no existen.

edgelist <- edgelist[!(edgelist$from %in% mis | edgelist$to %in% mis), ]

Ahora podemos intentar crear otra vez nuestra base de datos

g <- graph_from_data_frame(edgelist, directed=FALSE, vertices=atributos)

y transformarla a un objeto de statnet usando la función asNetwork de intergraph.

g <- asNetwork(g)
plot(g)

El paquete statnet funciona de forma diferente, y un poco más complicada, que igraph. Por ejemplo, si queremos ver el vector de atributos de un vértice podemos usar la función %v%

head(g %v% "grupo")
head(g %v% "edad")

El formato statnet nos permite usar las funciones de ergm para la estimación de modelos. Por ejemplo, podemos investigar si la probabilidad de formar aristas entre dos nodos depende del género o de la edad de los diputados. Pero antes de pasar ahí, quizás sea buena idea empezar con el modelo de Erdos-Renyi, que contiene un único término que captura la densidad de la red como función de una probabilidad homogénea de formar aristas.

summary(ergm(g ~ edges))

Podemos ahora testar si la probabilidad de formar aristas depende del partido político al que pertenece cada diputado. En este caso, queremos controlar por el número de aristas adyacentes a cada nodo.

basemodel <- ergm(g ~ edges + nodematch("grupo"))
summary(basemodel)

No es sorpresa que los términos sean estadísticamente significativos, ya que hemos visto que las redes están altamente organizadas alrededor de los partidos. Lo que el resultado nos dice es que las aristas es más probable que se formen entre vértices de un mismo partido. Otra forma de enfocar esta pregunta es mirando a la homofilia por partido. En ese caso, podríamos tener partidos más dispuestos a colaborar que otros.

basemodeldiff <- ergm(g ~ edges + nodematch("grupo", diff=TRUE))
summary(basemodeldiff)

La única sorpresa quizás sea el término -Inf en la variable que captura Grupo Vasco. Pero puede explicarse mirando a los descriptivos de la red.

mixingmatrix(g, "grupo")

Un elemento fundamental en el análisis de redes es la simulación. Podemos usar una simulación para ver hasta qué punto el modelo que hemos propuesto refleja correctamente la estructura subyacente de la red. Simular una red a través de un modelo en statnet es sencillo:

plot(simulate(basemodeldiff))

La red captura la concentración en clusters, pero está mucho más conectada que la red real, así que plantea dudas sobre la validez del modelo. Si el grupo político fuese el único determinante de la formación de aristas, tendríamos una red mucho más densamente conectada. Podemos ser un poco más precisos en esta aserción mirando a medidas de bondad de ajuste para ver hasta qué punto nuestro modelo ajusta los datos.

gof_base <- gof(basemodel)
plot(gof_base)

Podemos intentar contrastar otras teorías y añadir más términos a nuestro modelo. Por ejemplo, podemos estar interesados en un efecto generacional en la formación de las redes de colaboración. En ese caso, podríamos estar interesados en ver si hay una tendencia de los diputados a colaborar con gente de su edad.

expmodel <- ergm(g ~ edges + nodematch("grupo") + absdiff("edad"))
summary(expmodel)

El efecto es significativo, lo cual indica homofilia por edad, pero no vemos un mejor ajuste del modelo a los datos.

gof_exp <- gof(expmodel)
plot(gof_exp)

Podemos intentar otras explicaciones quizás más plausibles. Por ejemplo, quizás no sea la edad lo que marque las diferencias en la colaboración, sino tal vez la antigüedad en el Congreso, quizás como forma de medir la relación entre nuevos y viejos partidos (o al menos nuevos y viejos congresistas). O también podemos pensar en redes de colaboración territorial en la que los diputados de la misma región es más probable que colaboren.