Analítica de Personas · Semestre otoño 2026 · Semana 12 · Prof. René Gempp
Las métricas de centralidad que calculaste en el Apunte 29 son números. Un número te dice que la persona X tiene betweenness = 0.117. Pero no te dice dónde está X en la estructura, ni entre qué grupos funciona como puente, ni cuán aislado está un departamento del resto. Para eso necesitas un sociograma: la representación visual del grafo.
El paquete ggraph extiende ggplot2 para graficar redes. Su sintaxis es análoga: ggraph() reemplaza a ggplot(), geom_node_point() reemplaza a geom_point(), y geom_edge_link() es un geom nuevo para las aristas. Si sabes usar ggplot2, ya sabes la mitad de ggraph.
ggraph(): la gramática de los gráficos para redesUn gráfico de red con ggraph tiene tres capas obligatorias:
ggraph(grafo, layout = "...") — inicializa el gráfico y elige el layout.geom_edge_*() — dibuja las aristas.geom_node_*() — dibuja los nodos.library(ggraph)
set.seed(42) # reproducibilidad del layout
ggraph(red_tidy, layout = "fr") +
geom_edge_link(alpha = 0.05, color = "grey60") +
geom_node_point(aes(color = departamento), size = 2) +
theme_graph()
set.seed() antes de ggraph().
El layout determina la posición espacial de cada nodo. No hay un layout "correcto" — cada uno revela aspectos distintos de la estructura.
| Layout | Algoritmo | Cuándo usarlo |
|---|---|---|
"fr" | Fruchterman-Reingold | El más popular. Nodos conectados se atraen, no conectados se repelen. Bueno para ver clusters. |
"kk" | Kamada-Kawai | Minimiza la diferencia entre la distancia visual y la distancia en el grafo. Más estable que FR. |
"stress" | Stress majorization | Similar a KK pero más robusto para redes grandes. Recomendado como alternativa a FR. |
"circle" | Circular | Nodos en un círculo. Útil para ver la densidad de aristas sin que los clusters dominen. |
"linear" | En línea | Nodos en una línea horizontal. Útil para comparar dos mitades o para redes bipartitas. |
# Comparar dos layouts
p1 <- ggraph(red_tidy, layout = "fr") +
geom_edge_link(alpha = 0.03) +
geom_node_point(size = 1) +
labs(title = "Fruchterman-Reingold") +
theme_graph()
p2 <- ggraph(red_tidy, layout = "kk") +
geom_edge_link(alpha = 0.03) +
geom_node_point(size = 1) +
labs(title = "Kamada-Kawai") +
theme_graph()
p1 + p2 # requiere library(patchwork)
geom_edge_link()Las aristas se dibujan con geom_edge_link() (líneas rectas) o geom_edge_arc() (arcos curvos). Los parámetros estéticos más útiles:
geom_edge_link(
alpha = 0.06, # transparencia (bajo = menos ruido visual)
color = "grey60", # color fijo
aes(width = peso) # grosor por peso (si la arista tiene peso)
)
geom_node_point() y etiquetasgeom_node_point(
aes(
color = departamento, # color por atributo categórico
size = cent_betweenness # tamaño por centralidad
),
alpha = 0.7
)
# Etiquetas solo para los nodos más centrales
geom_node_text(
aes(label = ifelse(
cent_betweenness > quantile(cent_betweenness, 0.99),
nombre, ""
)),
size = 2.5,
repel = TRUE, # evita superposición de etiquetas
max.overlaps = 15
)
ifelse() para etiquetar solo los nodos con centralidad por encima de un umbral (e.g., percentil 99).
facet_nodes()Al igual que ggplot2 tiene facet_wrap(), ggraph tiene facet_nodes() para crear un panel por cada valor de un atributo de nodo:
ggraph(red_tidy, layout = "fr") +
geom_edge_link(alpha = 0.05) +
geom_node_point(aes(color = departamento), size = 1) +
facet_nodes(~ departamento, scales = "free") +
theme_graph()
Cada panel muestra la subred de un departamento. Las aristas que cruzan paneles se dibujan tenuemente. Esto permite comparar la estructura interna de cada departamento.
Una comunidad en una red es un subgrupo de nodos que están más densamente conectados entre sí que con el resto de la red. Es el equivalente reticular de un cluster.
La calidad de una partición en comunidades se mide con la modularidad (Q): compara la densidad de aristas dentro de cada comunidad con la que se esperaría al azar.
Valores de Q por encima de 0.3–0.4 indican estructura comunitaria fuerte (Newman, 2006). Una Q ≈ 0.54 como la de InnovaCo indica comunidades muy marcadas.
cluster_louvain()El algoritmo de Louvain (Blondel, Guillaume, Lambiotte & Lefebvre, 2008) optimiza la modularidad de forma iterativa. Es rápido, escalable, y es el algoritmo más utilizado en la práctica.
set.seed(42)
comunidades <- cluster_louvain(red)
# ¿Cuántas comunidades?
length(unique(membership(comunidades)))
# ¿Qué tan buena es la partición?
modularity(comunidades)
# → Q ≈ 0.54 → estructura comunitaria fuerte
# Agregar al grafo
red_tidy <- red_tidy |>
activate(nodes) |>
mutate(comunidad = as.factor(membership(comunidades)))
# Visualizar
ggraph(red_tidy, layout = "fr") +
geom_edge_link(alpha = 0.04) +
geom_node_point(aes(color = comunidad), size = 1.5) +
labs(title = "Comunidades detectadas por Louvain") +
theme_graph()
cluster_walktrap()El algoritmo walktrap (Pons & Latapy, 2006) detecta comunidades basándose en caminatas aleatorias: una caminata que empieza dentro de una comunidad tiende a quedarse ahí antes de salir.
com_walktrap <- cluster_walktrap(red)
modularity(com_walktrap)
La pregunta central del ONA es: ¿la estructura informal (comunidades detectadas) coincide con la estructura formal (departamentos del organigrama)?
# Tabla cruzada: comunidad × departamento
red_tidy |>
activate(nodes) |>
as_tibble() |>
count(comunidad, departamento) |>
pivot_wider(names_from = departamento, values_from = n, values_fill = 0)
Tres escenarios posibles:
La información novedosa no fluye por los lazos fuertes (amigos cercanos, colegas directos) sino por los lazos débiles (conocidos de otros departamentos). Los lazos fuertes conectan personas similares que comparten la misma información. Los lazos débiles cruzan círculos sociales y traen información nueva. Implicancia: las conexiones entre departamentos son potencialmente más valiosas para la innovación que las conexiones dentro del departamento.
Un hueco estructural (structural hole) es una brecha en la red entre dos grupos desconectados. Las personas que cierran estos huecos — los brokers — obtienen ventajas competitivas: acceso a información no redundante, control del flujo, y visibilidad ante múltiples audiencias. La betweenness centrality captura exactamente esta posición.
James Coleman argumentó que las redes densas y cerradas (closure) facilitan la confianza, las normas compartidas y la cooperación. Burt argumentó que las redes abiertas con huecos (brokerage) facilitan la innovación. Ambos tienen razón: los equipos necesitan cohesión interna (closure) y conexiones externas (brokerage). Una red que solo tiene una u otra es disfuncional.
| Aplicación | Pregunta | Métrica clave |
|---|---|---|
| Diagnóstico de silos | ¿Qué departamentos no se hablan? | Densidad interdepartamental, comunidades vs. organigrama |
| Key person risk | ¿Qué pasa si X se va? | Betweenness, simulación de eliminación de nodo |
| Integración post-fusión | ¿Se integraron las dos empresas? | Comunidades antes/después, aristas inter-empresa |
| Identificar influencers | ¿Quién mueve la opinión? | Eigenvector centrality |
| Onboarding | ¿Los nuevos se están integrando? | Degree y closeness de empleados nuevos a los 3, 6, 12 meses |
| DEI relacional | ¿Los grupos minoritarios están integrados en la red? | Centralidad por grupo demográfico |
Un mapa de red organizacional es una herramienta de poder. Saber quién conecta con quién, quién está aislado, quién es periférico — esa información puede usarse para apoyar o para controlar. La ética del ONA requiere tres condiciones:
| Función / paquete | Uso | Apunte |
|---|---|---|
igraph::graph_from_data_frame() | Crear grafo desde edgelist + nodos | 29 4 |
igraph::vcount(), ecount() | Número de nodos y aristas | 29 5 |
igraph::graph.density(), diameter() | Métricas globales de la red | 29 6 |
tidygraph::as_tbl_graph() | Convertir igraph a formato tidy | 29 7 |
tidygraph::activate() | Seleccionar tabla activa (nodos o aristas) | 29 7 |
centrality_degree() | Centralidad de grado | 29 9 |
centrality_betweenness() | Centralidad de intermediación | 29 10 |
centrality_closeness() | Centralidad de cercanía | 29 11 |
centrality_eigen() | Centralidad de vector propio | 29 12 |
igraph::delete_vertices() | Simular eliminación de un nodo | 29 14 |
ggraph::ggraph() | Inicializar gráfico de red | 30 2 |
ggraph::geom_edge_link() | Dibujar aristas | 30 4 |
ggraph::geom_node_point() | Dibujar nodos | 30 5 |
ggraph::facet_nodes() | Paneles por atributo de nodo | 30 6 |
igraph::cluster_louvain() | Detección de comunidades (Louvain) | 30 8 |
igraph::cluster_walktrap() | Detección de comunidades (walktrap) | 30 9 |
igraph::membership() | Asignación de comunidad por nodo | 30 8 |
igraph::modularity() | Calidad de la partición | 30 7 |