Apunte 29 — Redes organizacionales: igraph y tidygraph

Analítica de Personas · Semestre otoño 2026 · Semana 12 · Prof. René Gempp

1. ¿Por qué las relaciones importan?

Durante 11 semanas has analizado datos donde cada fila era un empleado y cada columna un atributo: edad, departamento, satisfacción, salario. Esa perspectiva — llamada centrada en variables — es la columna vertebral de la estadística aplicada. Pero tiene un punto ciego: no ve las relaciones entre personas.

Un empleado puede tener alta satisfacción, buen desempeño y bajo riesgo de rotación según todos tus modelos — y ser, al mismo tiempo, el único canal de comunicación entre dos departamentos. Si se va, tu modelo de rotación no detecta el problema. Lo que necesitas es una herramienta que mire la estructura de las relaciones, no solo los atributos individuales.

Esa herramienta es el análisis de redes sociales (Social Network Analysis, SNA), y su aplicación en organizaciones se llama ONA (Organizational Network Analysis). En esta clase pasamos del paradigma centrado en variables al paradigma reticular — centrado en relaciones (Borgatti, Mehra, Brass & Labianca, 2009).

DimensiónCentrado en variablesCentrado en relaciones
Unidad de análisisLa personaLa relación (díada)
Estructura de datosTabla rectangular (CSV)Grafo (nodos + aristas)
Pregunta típica¿Qué variables predicen Y?¿Qué posición en la red se asocia con Y?
Supuesto claveObservaciones independientesLas personas conectadas se influyen
Softwarelm(), glm(), psychigraph, tidygraph, ggraph
Conexión con la Clase 11. La semana pasada construiste una red de co-ocurrencia de palabras con igraph y ggraph. Esta semana construyes una red de personas. Las herramientas son las mismas; lo que cambia es lo que representan los nodos.

2. ¿Qué es un grafo?

Un grafo es un objeto matemático compuesto por:

Cada arista puede tener propiedades adicionales:

En R, el paquete igraph representa grafos como objetos especiales que almacenan nodos, aristas y sus propiedades. No son data frames — son estructuras propias que requieren funciones específicas para manipular.

3. Tipos de redes organizacionales

Cross y Parker (2004) identificaron cuatro redes que coexisten en toda organización:

Tipo de redPregunta generadora¿Qué mide?
Comunicación"¿Con quién hablas regularmente de trabajo?"Flujo de información operativa
Consejo"¿A quién acudes cuando necesitas consejo técnico?"Flujo de conocimiento experto
Confianza"¿En quién confías para compartir información delicada?"Capital social relacional
Energía"¿Después de interactuar con quién te sientes más motivado?"Contagio emocional positivo
Una misma organización tiene múltiples redes. La persona a quien acudes para consejo técnico puede no ser la misma en quien confías para temas delicados. Si solo mapeas una red, estás viendo solo una capa de la realidad relacional.

4. Crear un grafo: graph_from_data_frame()

El punto de entrada más común es un edgelist: una tabla con dos columnas (from, to) donde cada fila es una relación. Opcionalmente, una segunda tabla contiene los atributos de los nodos.

library(igraph)

# Edgelist: quién colabora con quién
aristas <- read_csv("innovaco_red_colaboracion.csv")

# Atributos de nodos: departamento, cargo, etc.
nodos <- empleados |>
  filter(rotacion == "No") |>
  select(id_empleado, nombre, departamento, cargo, antiguedad_anios)

# Crear el grafo
red <- graph_from_data_frame(
  d        = aristas,   # edgelist
  directed = FALSE,     # colaboración = recíproca
  vertices = nodos      # atributos de nodos
)

red
# → IGRAPH UN-- 874 2464 --
# → U = undirected, N = named
directed = FALSE crea una red no dirigida: si A colabora con B, se asume que B colabora con A. Para redes de consejo (donde la dirección importa: "yo consulto a X" no implica "X me consulta"), usa directed = TRUE.

5. Explorar un grafo: funciones básicas de igraph

# ¿Cuántos nodos y aristas?
vcount(red)   # → 874 nodos
ecount(red)   # → 2464 aristas

# Acceder a nodos y aristas
V(red)        # los vértices (nodos)
E(red)        # las aristas (edges)

# Ver atributos de un nodo específico
V(red)["INN-0343"]$nombre
V(red)["INN-0343"]$departamento

# ¿Cuántos contactos tiene un nodo?
degree(red, v = "INN-0343")

6. Métricas globales de la red

Antes de analizar nodos individuales, necesitas entender la red completa.

# Densidad: aristas existentes / aristas posibles
graph.density(red)
# → ~0.006 → red muy dispersa

# Diámetro: camino más largo entre cualquier par
diameter(red)
# → 9 → máximo 9 saltos entre las personas más lejanas

# ¿La red tiene un solo componente?
is_connected(red)
components(red)$no

# Transitividad (clustering): ¿los amigos de mis amigos son mis amigos?
transitivity(red, type = "global")

# Distancia promedio entre todos los pares
mean_distance(red)
Interpretación ejecutiva. Una densidad de 0.006 significa que cada persona colabora con menos del 1% de la organización. Un diámetro de 9 significa que la información tarda hasta 9 "saltos" en llegar de un extremo al otro. Para un CEO, esto implica que un comunicado enviado por email puede necesitar hasta 9 intermediarios para llegar a quien más lo necesita — si la vía es informal.

7. tidygraph: la interfaz tidy para grafos

El paquete tidygraph envuelve un objeto igraph en una interfaz compatible con dplyr. El grafo tiene dos "tablas" internas — una de nodos y una de aristas — y puedes operar sobre cada una con los verbos que ya conoces: mutate(), filter(), arrange(), select().

library(tidygraph)

red_tidy <- as_tbl_graph(red)
red_tidy
# → # A tbl_graph: 874 nodes and 2464 edges

# Activar la tabla de nodos
red_tidy |>
  activate(nodes) |>
  as_tibble() |>
  count(departamento, sort = TRUE)

# Activar la tabla de aristas
red_tidy |>
  activate(edges) |>
  as_tibble() |>
  count(tipo, sort = TRUE)

# Agregar columnas a los nodos (como mutate en un df)
red_tidy <- red_tidy |>
  activate(nodes) |>
  mutate(n_contactos = centrality_degree())
activate() es la clave. Siempre debes decirle a tidygraph sobre cuál tabla quieres operar: activate(nodes) o activate(edges). Si no activas, opera sobre la última tabla activada (por defecto, nodos).

8. Operar con dplyr sobre el grafo

Una vez activada la tabla de nodos, puedes usar cualquier verbo de dplyr:

# Top 10 nodos por grado
red_tidy |>
  activate(nodes) |>
  as_tibble() |>
  arrange(desc(n_contactos)) |>
  select(nombre, departamento, cargo, n_contactos) |>
  head(10)

# Filtrar: solo nodos de Desarrollo de Software
red_tidy |>
  activate(nodes) |>
  filter(departamento == "Desarrollo de Software")
# → Devuelve un subgrafo con solo esos nodos y sus aristas internas

9. Degree centrality: ¿quién tiene más contactos?

La centralidad de grado (degree) es la métrica más simple: cuenta cuántas conexiones directas tiene un nodo. Normalizada, divide por el máximo posible (n − 1).

CD(i) = ki / (n − 1)
red_tidy <- red_tidy |>
  activate(nodes) |>
  mutate(cent_degree = centrality_degree(normalized = TRUE))
¿Cuándo importa el degree? Cuando necesitas difundir información rápidamente. Las personas con alto degree conocen a mucha gente y son amplificadores naturales. Pero tener muchos contactos no garantiza tener los contactos correctos.

10. Betweenness centrality: ¿quién es un puente?

La centralidad de intermediación (betweenness) cuenta cuántos caminos más cortos entre otros pares de nodos pasan por un nodo dado. Es la métrica más importante para identificar brokers y evaluar key person risk.

CB(i) = Σs≠i≠t σst(i) / σst
red_tidy <- red_tidy |>
  activate(nodes) |>
  mutate(cent_betweenness = centrality_betweenness(normalized = TRUE))
Degree ≠ betweenness. Una persona puede tener 5 contactos (bajo degree) pero ser el único puente entre 200 personas (alta betweenness). Si esa persona se va, se fragmenta la red. Es la diferencia entre ser popular y ser imprescindible.

11. Closeness centrality: ¿quién está más cerca de todos?

La centralidad de cercanía (closeness) es el inverso de la suma de las distancias más cortas desde un nodo a todos los demás. Las personas con alta closeness están "geográficamente" en el centro de la red.

red_tidy <- red_tidy |>
  activate(nodes) |>
  mutate(cent_closeness = centrality_closeness(normalized = TRUE))

Cuándo importa: cuando necesitas que un mensaje llegue a todos con la menor distorsión posible (comunicación de crisis).

12. Eigenvector centrality: ¿quién conoce a los importantes?

La centralidad de vector propio (eigenvector) no solo cuenta cuántas conexiones tienes, sino cuán conectados están tus contactos. Si tus pocos contactos son a su vez muy centrales, tu eigenvector centrality es alta. Es una medida de influencia por asociación.

red_tidy <- red_tidy |>
  activate(nodes) |>
  mutate(cent_eigenvector = centrality_eigen(scale = TRUE))

Cuándo importa: cuando buscas influencia indirecta. El PageRank de Google es una variante de eigenvector centrality: una página es "importante" si otras páginas "importantes" la enlazan.

13. Comparación de métricas: no miden lo mismo

MétricaPreguntaMetáforaSi sale de la empresa...
Degree¿Quién conoce a más gente?El "gregario"Se pierde un nodo activo, pero hay redundancia
Betweenness¿Quién conecta partes separadas?El "puente"Se fragmenta la red — riesgo máximo
Closeness¿Quién alcanza a todos más rápido?El "centro geográfico"Se alarga la distancia promedio
Eigenvector¿Quién conoce a los importantes?El "bien conectado"Se pierde acceso a la red de influencia
# Correlación entre métricas
metricas |>
  select(starts_with("cent_")) |>
  cor() |>
  round(3)
# → Si r es baja entre degree y betweenness,
#   "popular" y "puente" son roles distintos

14. Key person risk: simular la eliminación de un nodo

La forma más directa de evaluar el riesgo de persona clave es eliminar el nodo del grafo y comparar las métricas antes y después. Si el diámetro sube, la red se alarga. Si aparecen componentes nuevos, la red se fragmentó. Si la distancia promedio sube mucho más de lo esperado, la persona era un puente crítico.

# Identificar al broker principal
top_broker <- metricas |>
  slice_max(cent_betweenness, n = 1)

# Métricas originales
mean_distance(red)      # distancia promedio original

# Eliminar al broker
red_sin <- delete_vertices(red, top_broker$name)

# Métricas post-eliminación
mean_distance(red_sin)  # ¿cuánto subió?
components(red_sin)$no  # ¿se fragmentó?
diameter(red_sin)       # ¿se alargó?

# Comparar con un nodo aleatorio
red_random <- delete_vertices(red, sample(V(red)$name, 1))
mean_distance(red_random)
# → Si la diferencia es grande, el broker era crítico
Plan de sucesión relacional. El plan de sucesión clásico se enfoca en las competencias del sucesor. El plan de sucesión relacional se enfoca en que el sucesor construya las relaciones que la persona clave tiene — antes de que se vaya. Esto requiere un periodo de transición donde el sucesor asiste a reuniones, proyectos y espacios informales junto con la persona que se va.

15. Resumen y conexión con el Apunte 30

En este apunte aprendiste a construir grafos (graph_from_data_frame()), explorarlos (vcount(), ecount(), graph.density(), diameter()), operar sobre ellos con la interfaz tidy (tidygraph), calcular las cuatro métricas de centralidad (centrality_degree(), centrality_betweenness(), centrality_closeness(), centrality_eigen()), y simular la eliminación de nodos para evaluar el key person risk.

En el Apunte 30 aprenderás a visualizar estas redes con ggraph (layouts, colores, tamaños), a detectar comunidades (Louvain, walktrap) y a compararlas con la estructura formal (organigrama), y a conectar todo con los marcos teóricos de Granovetter, Burt y Coleman.