Entre las numerosas aplicaciones que tienen los algoritmos del software R, especializado en minería de datos y análisis de redes, hemos encontrado una que puede ayudar a los departamentos de Recursos Humanos y a los jefes de proyecto a analizar mejor los equipos de trabajo, solamente teniendo la información de la cantidad de correos electrónicos internos que las personas se envían entre sí.
Este tipo de análisis de redes no es intrusivo, porque no se entra a analizar el contenido de los mismos, si acaso “violando” la intimidad de las personas. Por el contrario, se analiza al equipo de trabajo en su conjunto para comprender mejor su funcionamiento procurando identificar los problemas antes de que se produzcan, teniendo pues un propósito meramente profesional.
Para ello, hemos recopilado en un archivo csv, la cantidad de correos que un ficticio equipo de 14 personas se envía entre sí. En las filas hemos escrito el origen o la persona que ha enviado el correo, y en la columna, el destinatario del mismo, tal y como muestra el gráfico 1. De ese modo podemos ver que la Persona 1 ha enviado 3 correos a la Persona 2. Y a su vez, la Persona 2, ha enviado 5 correos a la Persona 1.
En primer lugar, importamos los datos del directorio en donde se encuentren con esta orden, indicándole que el separador de campos es un “;”, los valores que figuran como “missing”, que nos borre los caracteres en blanco no significativos y el código de caracteres que usamos.
Transformamos los datos leídos en una matriz evitando los nombres de las personas que figuran en la columna 1 y que al no ser numéricos, no se va a poder trabajar con ellos. Recordemos que el equipo lo forman 14 personas y que en este vamos a obtener una matriz cuadrada de orden 14, teniendo los nombres de las personas, como nombres de las columnas con las que vamos a trabajar y que se pueden obtener con la orden “colnames(mat)”
> mat <- as.matrix(Dataset[,2:15])
Cargamos en memoria las librerías con las que vamos a trabajar.
- “igraph” .- sirve para analizar y visualizar las redes
> library(igraph)
Convertimos la matriz cuadrada en un gráfico dirigido, ya que no es lo mismo enviar que recibir correos, indicando que los números que figuran en la matriz son el peso que tienen las flechas que relacionan los puntos o nodos de la red y dibujamos la red para tener una primera idea.
> g1 <- graph.adjacency(mat, weighted = T, mode = ‘directed’)
> plot(g1,edge.width=2)
En primer lugar, existe la posibilidad de crear subredes para estudiarlas con más detalle, por ejemplo, eligiendo aquellas relaciones con más de 6 correos, considerando que por debajo de esa cantidad, han sido todos ceros, en donde pueden apreciarse los subgrupos significativos dentro de la red y que ha desaparecido la Persona 1 de este gráfico.
> g2 <- subgraph.edges(g1, which(E(g1)$weight > 6))
> plot(g2,edge.width=2)
Aunque este no ha sido el caso, se puede depurar la red de aquellos elementos extraños que son: en primer lugar los correos que uno se manda a sí mismo, o auto-loops, o las flechas que pueden estar duplicadas, con los mismos orígenes y destinos.
> g1 <- simplify(g1, remove.loops = TRUE, remove.multiple = TRUE)
Comenzamos ahora con el análisis numérico de la red, examinado el número de entradas y salidas que tiene cada nodo
> in1 <- as.data.frame(igraph::degree(g1,mode = ‘in’))
> library(ggplot2)
> ggplot(in1,aes(rownames(in1))) + geom_bar(aes(weight=in1,fill=in1)) + coord_flip()
> out1 <- as.data.frame(igraph::degree(g1,mode = ‘out’))
> ggplot(out1,aes(rownames(out1))) + geom_bar(aes(weight=out1,fill=out1)) + coord_flip()
Ahora vamos a empezar a aplicar las valoraciones de los distintos nodos de la red que propone la teoría matemática de redes. En primer lugar el concepto de intermediación, mide la cantidad de veces que un nodo concreto (n1), aparece en el camino más corto entre dos nodos cualesquiera. De ese modo, significa que el nodo n1, ejerce de intermediario para las comunicaciones entre dos personas cualesquiera. Este valor puede darse normalizado de forma que todos los nodos sumen un 100%, o no, en este último caso, el valor se calcula como el número de veces que es intermediario dividido por el número de ocasiones posibles, como puede verse en este enlace. Este concepto puede interpretarse como “valor añadido de la comunicación”, que será superior según su valor sea más alto.
> bet1 <- as.data.frame(round(igraph::betweenness(g1),3))
> rownames(bet1) <- colnames(mat)
> ggplot(as.data.frame(bet1[,1]),aes(rownames(bet1))) + geom_bar(aes(weight=bet1,fill=bet1 )) + coord_flip()
Otra métrica a tener en cuenta la cercanía que tiene cada nodo respecto de los demás. La idea intuitiva es fácil, la distancia entre cada nodo se mide por la longitud del camino más corto. De esa manera, si tomamos un cierto nodo n1 y sumamos todas las distancias, o todas las longitudes de los caminos más cortos, respecto de todos los demás puntos, tendremos una idea de cercanía o lejanía de ese punto respecto de la red. En este caso, la cercanía se define como el inverso de ese valor, como puede leerse en este enlace.
Lógicamente cuanto menor es la distancia de un punto de la red, el inverso de ese valor, su cercanía, es mayor. Y caso contrario, cuanto mayor es la distancia, su cercanía es menor. Siendo el hecho de si la red está dirigida o no lo está, muy importante, puesto que la distancia entre dos puntos podría ser simétrica o no serlo. Si está dirigida, es decir, si la distancia no es simétrica, entonces el concepto de cercanía, es mucho más importante.
> clo1 <- as.data.frame(round(igraph::closeness(g1),3))
> rownames(clo1) <- colnames(mat)
> ggplot(as.data.frame(clo1[,1]),aes(rownames(clo1))) + geom_bar(aes(weight=clo1,fill=clo1 )) + coord_flip()
También podemos establecer una métrica al estilo del algoritmo “page-rank” de Google, en donde se mide la importancia del nodo en la red examinando cuáles son los nodos muy conectados que están conectados con otros nodos muy conectados, llamado también Eigencentrality porque utiliza los eigenvalores de los nodos para medir dicha influencia en la red.
> ev1 <- as.data.frame(round(eigen_centrality(g1)$vector,3))
> rownames(ev1) <- colnames(mat)
> ggplot(as.data.frame(ev1[,1]),aes(rownames(ev1))) + geom_bar(aes(weight=ev1,fill=ev1 )) + coord_flip()
También, pero esta vez tratando las relaciones y no los nodos, podemos medir la importancia de la intermediación de cada relación en la red, mostrar en este caso las 6 más importantes. En este ejemplo, la más importante de todas, entre las personas 10 y 7, es un solo correo que sirve para unir dos subgrupos del equipo que parecen estar “un poco incomunicados”, como puede verse en el gráfico 2.
En este caso podemos crear una subred con las relaciones más importantes.
g3 <- subgraph.edges(g1, which(edge_betweenness(g1)>10))
plot(g3,edge.width=2)
El concepto de restricción se basa en la calidad de información que un nodo puede recibir y nos explicamos, si dos nodos tienen fuertes relaciones, entonces es muy probable que compartan muchos contactos y muchas de sus relaciones con terceros sean semejantes, por lo que lo más probable es que reciban el mismo tipo de información. Caso contrario, si las relaciones son débiles, es menos probable que reciban el mismo tipo de información, por lo que pueden estar mejor informadas de temas variados. Este índice en concreto, refleja ese valor de la variedad del tipo de información que pudiera recibirse. Este concepto puede ampliarse en este enlace.
> con1 <- as.data.frame(round(igraph::constraint(g1),3))
> rownames(con1) <- colnames(mat)
> ggplot(as.data.frame(con1[,1]),aes(rownames(con1))) + geom_bar(aes(weight=con1,fill=con1 )) + coord_flip()
Un concepto más sencillo es ver la densidad de la red media como el cociente entre relaciones reales y relaciones posibles, lo que nos da una idea del grado de comunicación y de la calidad de las relaciones internas.
> graph.density(g1)
[1] 0.3516484
En un análisis más visual podemos detectar los llamados “grupitos” que se pueden formar dentro de un equipo de trabajo, tanto para bien como para mal, y a los que hay que encontrar un sentido.
> com <- edge.betweenness.community(g1)
> V(g1)$memb <- com$membership
> plot(com, g1)
También podemos dibujar en el gráfico cualquier resultado de todos los indicadores que hemos calculado. En este caso, vamos a estudiar el resultado de la calidad de la información que puede tener cada nodo
> con <- round(constraint(g1),1)
> con <- paste(get.vertex.attribute(g1)$name,”-“,con)
> plot(g1, vertex.label=con,edge.width=2)
Ahora podemos juntar los resultados más importantes de los nodos en un único data-frame y analizar los nodos en su conjunto, para ver si se corresponden con el rendimiento esperado del equipo.
todo1 <- cbind(bet1,clo1,ev1,con1)
colnames(todo1) <- c(‘intermedio’,’cercano’,’contactos’,’informacion’)
ggplot(data=todo1,aes(x=intermedio,y=cercano))+ geom_text(aes(label=rownames(todo1),color=informacion,size=contactos))
Para terminar, sólo decir que con estas órdenes podemos extraer los datos de la red para realizar otros estudios
> g1.v <- get.data.frame(g1, what = “vertices”)
> g1.e <- get.data.frame(g1, what = “edges”)
Autor: Pedro José Jiménez, profesor del Máster en Big Data y Business Intelligence