Introducción

La cohesión o conectividad se refiere a la medida en que subconjuntos de vértices específicos son cohesivos (adherentes) respecto a la relación que define las aristas.

Cliques

Un enfoque para definir la cohesión de una red es mediante la especificación de subgrafos de interés.

Un clan (clique) \(C\) de un grafo \(G=(V,E)\) es un subconjunto de vértices tal que cada par de vértices distintos son adyacentes, i.e., el subgrafo de \(G\) inducido por \(C\) es un grafo completo.

Clanes de tamaños más grandes incluyen clanes de tamaños más pequeños.

¿Cuántos clanes?

# librerias
suppressMessages(suppressWarnings(library(igraph)))
suppressMessages(suppressWarnings(library(corrplot)))
# datos
g <- make_graph(
       edges = c(1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,6,7,6,8,7,8,9,10,1,6,2,9,7,9), 
       directed = F
     )
Y <- as.matrix(as_adjacency_matrix(graph = g, names = F))
# visualización
par(mfrow = c(1,2), mar = c(4, 3, 3, 1))
set.seed(42)

plot(g, 
     vertex.size = 20, 
     vertex.color = 0, 
     vertex.label.color = "black", 
     edge.color = "blue4")

corrplot(corr = Y, 
         col.lim = c(0,1), 
         method = "color", 
         tl.col = "black", 
         addgrid.col = "gray", 
         cl.pos = "n")

# orden
vcount(g)
## [1] 10
# tamaño
ecount(g)
## [1] 17
# clan?
c1 <- induced_subgraph(graph = g, vids = c(6,7,8))
ecount(c1) == choose(n = vcount(c1), k = 2)
## [1] TRUE
# frecuencias de clanes
table(sapply(X = cliques(graph = g, min = 1, max = 10), FUN = length))
## 
##  1  2  3  4  5 
## 10 17 11  5  1

Un clan maximal (maximal clique) es un clan que no se puede extender incluyendo algún otro vértice.

# clanes maximales
max_cliques(graph = g)
## [[1]]
## + 2/10 vertices, from ea5de20:
## [1] 10  9
## 
## [[2]]
## + 3/10 vertices, from ea5de20:
## [1] 6 7 8
## 
## [[3]]
## + 2/10 vertices, from ea5de20:
## [1] 6 1
## 
## [[4]]
## + 2/10 vertices, from ea5de20:
## [1] 7 9
## 
## [[5]]
## + 2/10 vertices, from ea5de20:
## [1] 9 2
## 
## [[6]]
## + 5/10 vertices, from ea5de20:
## [1] 1 2 5 4 3

Un clan máximo (maximum clique) es el clan maximal más grande.

El número clan (clique number) es el tamaño del clan máximo.

# clanes máximos
largest_cliques(graph = g)
## [[1]]
## + 5/10 vertices, from ea5de20:
## [1] 1 2 5 4 3
# número clan
clique_num(graph = g)
## [1] 5

En la práctica, clanes “grandes” son escasos, ya que requieren que el grafo sea denso, dado que las redes reales tienden a ser dispersas (sparse).

Ejemplo: Interacciones sociales

Red de interacciones sociales entre los miembros de un club de karate.

Estos datos fueron recolectados para estudiar la fragmentación que sufrió el club en dos clubes diferentes debido a una disputa entre el director y el administrador.

\(y_{i,j} = 1\) si los miembros \(i\) y \(j\) tuvieron una interacción social en el club y \(y_{i,j} = 0\) en otro caso.

Una descripción completa de los datos se puede encontrar aquí.

Disponible en el paquete igraphdata de R.

Zachary, W. W. (1977). An information flow model for conflict and fission in small groups. Journal of anthropological research, 33(4), 452-473.

# install.packages("igraphdata")
suppressMessages(suppressWarnings(library(igraphdata)))

# data
data(karate)
karate <- upgrade_graph(karate)
# la representación de datos internos a veces cambia entre versiones
# orden
vcount(karate)
## [1] 34
# tamaño
ecount(karate)
## [1] 78
# dirigida?
is_directed(karate)
## [1] FALSE
# ponderada?
is_weighted(karate)
## [1] TRUE
# visualización
par(mar = c(4, 3, 3, 1))

set.seed(123)
plot(karate, 
     layout = layout_with_dh, 
     vertex.size = 10, 
     vertex.frame.color = "black", 
     vertex.label.color = "black", 
     main = "Interacciones sociales")

# clanes máximos
largest_cliques(graph = karate)
## [[1]]
## + 5/34 vertices, named, from 4b458a1:
## [1] Actor 2 Mr Hi   Actor 4 Actor 3 Actor 8
## 
## [[2]]
## + 5/34 vertices, named, from 4b458a1:
## [1] Actor 2  Mr Hi    Actor 4  Actor 3  Actor 14
# número clan
clique_num(graph = karate)
## [1] 5

Ejemplo: Interacciones proteína-proteína

Red de interacción de proteínas de levadura.

Las interacciones proteína-proteína prometen revelar aspectos del sistema regulatorio que subyace a la función celular.

Los nodos corresponden a proteínas y solo se consideran aquellas interacciones que tienen una confianza “moderada” y “alta”.

Una descripción completa de los datos se puede encontrar aquí.

Disponible en el paquete igraphdata de R.

Von Mering, C., Krause, R., Snel, B., Cornell, M., Oliver, S. G., Fields, S., & Bork, P. (2002). Comparative assessment of large-scale data sets of protein–protein interactions. Nature, 417(6887), 399-403.

# datos
data(yeast)
yeast <- upgrade_graph(yeast)
# la representación de datos internos a veces cambia entre versiones
# orden
vcount(yeast)
## [1] 2617
# tamaño
ecount(yeast)
## [1] 11855
# dirigida?
is_directed(yeast)
## [1] FALSE
# ponderada?
is_weighted(yeast)
## [1] FALSE
# número clan
clique_num(graph = yeast)
## [1] 23

El número clan es relativamente pequeño (incluso para redes “grandes”).

Díadas y tríadas

Otras cantidades de interés son las díadas y las tríadas.

¿Cuáles son los estados diádicos no dirigidos y dirigidos?

¿Y los triádicos?

Estados triádicos no dirigidos (undirected triadic motifs)

Estados triádicos dirigidos (directed triadic motifs)

  • Dado que una tríada tiene 3 pares no ordenados de nodos, los dígitos siempre suman 3. Por ejemplo, 021 significa 0 díadas mutuas, 2 díadas unidireccionales y 1 díada no conectada.

  • D (Down) indica una configuración descendente, en la que un nodo dirige arcos hacia otros dos nodos. Por ejemplo, \(A \to B\) y \(A \to C\).

  • U (Up) indica una configuración ascendente, en la que dos nodos dirigen arcos hacia un mismo nodo. Por ejemplo, \(A \to C\) y \(B \to C\).

  • T (Transitive) indica una configuración transitiva, en la que si un nodo se relaciona con un segundo y este con un tercero, entonces también existe relación entre el primero y el tercero. Por ejemplo, \(A \to B\), \(B \to C\) y \(A \to C\).

  • C (Cyclic) indica una configuración cíclica, en la que los tres nodos forman un ciclo dirigido. Por ejemplo, \(A \to B\), \(B \to C\) y \(C \to A\).

Davis, J.A. and Leinhardt, S. (1972). The Structure of Positive Interpersonal Relations in Small Groups. In J. Berger (Ed.), Sociological Theories in Progress, Volume 2, 218-251. Boston: Houghton Mifflin.

Un censo de los estados diádicos o triádicos proporciona una medida de la conectividad de una red.

Puntuaciónes estandarizadas (z-scores)

La puntuación estandarizada normalizada de un motivo triádico dirigido mide qué tan más o menos frecuente es ese motivo en la red observada, respecto a lo esperado por azar bajo un modelo nulo (una versión aleatorizada de la red original usada como referencia).

Para cada motivo \(k\), primero se calcula \[ Z_k = \frac{N_k^{\text{obs}} - \textsf{E}(N_k^{\text{rand}})}{\textsf{SD}(N_k^{\text{rand}})}, \] donde \(N_k^{\text{obs}}\) es el número observado de ocurrencias del motivo, mientras que \(\textsf{E}(N_k^{\text{rand}})\) y \(\textsf{SD}(N_k^{\text{rand}})\) se estiman a partir de redes aleatorizadas. Luego, estos puntajes se normalizan como \[ \hat{z}_k = \frac{Z_k}{\sqrt{\sum_j Z_j^2}}. \] De esta forma, \(\hat{z}_k > 0\) indica que el motivo aparece más de lo esperado por azar, \(\hat{z}_k < 0\) indica que aparece menos de lo esperado, y su magnitud refleja su importancia relativa dentro del perfil global de motivos de la red.

Ejemplo: Blogs de SIDA

Red de blogs de SIDA, pacientes y sus redes de apoyo.

Un enlace dirigido de un blog a otro indica que el primero tiene un enlace al segundo en su página web.

Una descripción completa de los datos se puede encontrar aquí.

Disponible en el paquete sand de R.

Miller, H. J. (2007). Societies and cities in the age of instant access. In Societies and cities in the age of instant access (pp. 3-28). Springer, Dordrecht.

# librerías
suppressMessages(suppressWarnings(library(sand)))
# data
data(aidsblog)
aidsblog <- upgrade_graph(aidsblog)
# la representación de datos internos a veces cambia entre versiones
# orden
vcount(aidsblog)
## [1] 146
# tamaño
ecount(aidsblog)
## [1] 187
# dirigida?
is_directed(aidsblog)
## [1] TRUE
# ponderada?
is_weighted(aidsblog)
## [1] FALSE
# visualización
set.seed(123)
par(mfrow = c(1,1), mar = c(4, 3, 3, 1))
plot(aidsblog, 
     layout = layout_with_kk, 
     vertex.label = NA, vertex.size = 5, 
     vertex.frame.color = 1, 
     edge.arrow.size = 0.5, 
     main = "")

# simple?
is_simple(aidsblog)
## [1] FALSE
# simplificación
aidsblog <- simplify(aidsblog)
# censo de estados diádicos
#   mut   The number of pairs with mutual connections.
#   asym  The number of pairs with non-mutual connections.
#   null  The number of pairs with no connection between them.
dyad_census(aidsblog)
## $mut
## [1] 3
## 
## $asym
## [1] 177
## 
## $null
## [1] 10405
# censo de estados triádicos
#   003   A,B,C, the empty graph.
#   012   A->B, C, the graph with a single directed edge.
#   102   A<->B, C, the graph with a mutual connection between two vertices.
#   021D  A<-B->C, the out-star.
#   021U  A->B<-C, the in-star.
#   021C  A->B->C, directed line.
#   111D  A<->B<-C.
#   111U  A<->B->C.
#   030T  A->B<-C, A->C.
#   030C  A<-B<-C, A->C.
#   201   A<->B<->C.
#   120D  A<-B->C, A<->C.
#   120U  A->B<-C, A<->C.
#   120C  A->B->C, A<->C.
#   210   A->B<->C, A<->C.
#   300   A<->B<->C, A<->C, the complete graph.

# etiquetas de las 16 tríadas dirigidas
triad_labels <- c(
  "003",  "012",  "102",  "021D", "021U", "021C",
  "111D", "111U", "030T", "030C", "201",
  "120D", "120U", "120C", "210",  "300"
)

# censo de triadas
obs_counts <- triad_census(aidsblog)
names(obs_counts) <- triad_labels

obs_counts
##    003    012    102   021D   021U   021C   111D   111U   030T   030C    201 
## 484621  20717    300   2195     39     74      1    112      4      0      2 
##   120D   120U   120C    210    300 
##      0     15      0      0      0
# número de redes nulas
B <- 1000

# grados de salida y entrada del grafo observado
out_deg <- igraph::degree(aidsblog, mode = "out")
in_deg  <- igraph::degree(aidsblog, mode = "in")

# matriz para guardar los censos triádicos bajo el modelo nulo
null_counts <- matrix(
  NA_real_,
  nrow = B,
  ncol = length(triad_labels),
  dimnames = list(NULL, triad_labels)
)

# redes nulas dirigidas con la misma secuencia de grados
set.seed(123)
for (b in seq_len(B)) {
  g_null <- igraph::sample_degseq(
    out.deg = out_deg,
    in.deg  = in_deg,
    method  = "edge.switching.simple"
  )
  
  null_counts[b, ] <- igraph::triad_census(g_null)
}

# media y desviación estándar bajo el modelo nulo
mu_null <- colMeans(null_counts)
sd_null <- apply(X = null_counts, MARGIN = 2, FUN = sd)

# puntuaciones Z
# puntuaciones Z
z_scores <- ifelse(
  sd_null > 0,
  (obs_counts - mu_null) / sd_null,
  NA_real_
)

# versión normalizada
z_scores_norm <- z_scores / sqrt(sum(z_scores^2, na.rm = TRUE))

# tabla de resultados
triad_z <- data.frame(
  triad   = triad_labels,
  obs     = as.numeric(obs_counts),
  mean    = mu_null,
  sd      = sd_null,
  z       = z_scores,
  z_norm  = z_scores_norm,
  row.names = NULL
)

# tabla
triad_z
##    triad    obs       mean          sd            z        z_norm
## 1    003 484621 484422.185  73.2309740  2.714903123  0.2348336006
## 2    012  20717  21029.940 115.1413389 -2.717877028 -0.2350908373
## 3    102    300     85.416  74.2200078  2.891188056  0.2500818889
## 4   021D   2195   2277.961  35.5971718 -2.330550319 -0.2015878644
## 5   021U     39     38.977   3.8873619  0.005916609  0.0005117746
## 6   021C     74    161.789  36.9068096 -2.378666730 -0.2057498362
## 7   111D      1      0.544   0.7284192  0.626013115  0.0541488618
## 8   111U    112     41.287  35.3614913  1.999717699  0.1729715155
## 9   030T      4     18.867   5.3477013 -2.780073015 -0.2404706637
## 10  030C      0      0.467   0.6552407 -0.712715219 -0.0616484174
## 11   201      2      0.063   0.2551394  7.591929188  0.6566864400
## 12  120D      0      0.034   0.1813198 -0.187513975 -0.0162195776
## 13  120U     15      2.307   2.3584557  5.381911550  0.4655244074
## 14  120C      0      0.152   0.3647314 -0.416744980 -0.0360475935
## 15   210      0      0.011   0.1043546 -0.105409788 -0.0091177324
## 16   300      0      0.000   0.0000000           NA            NA
# visualización
par(mfrow = c(1, 1), mar = c(8, 4, 3, 1))
barplot(
  height = triad_z$z_norm,
  names.arg = triad_z$triad,
  las = 2,
  ylab = "Z-score normalizado",
  main = "Puntuaciones normalizadas de motivos triádicos dirigidos"
)
abline(h = 0, col = 2)

  • Valores con \(|z| \gtrsim 2\) sugieren diferencias importantes frente al modelo nulo.

  • Se observan más tríadas \(003\) y \(102\) de lo esperado por azar.

  • Se observan menos tríadas \(012\), \(021D\), \(021C\) y \(030T\) de lo esperado por azar.

  • La tríada \(111U\) muestra una sobrerrepresentación débil, cercana al umbral de significancia.

  • Las tríadas \(021U\), \(111D\) y \(030C\) no muestran evidencia clara de desviación frente al modelo nulo.

  • La red parece más dispersa y con menor presencia de estructuras triádicas organizadas, especialmente de tipo transitivo.

  • La gran mayoría de los estados son nulos y de los que no lo son, casi todos son asimétricos, lo que indica una unilateralidad (asimetría) preponderante en la manera en que los blogs se referencian.

Densidad

La densidad (density) de un grafo se define como la frecuencia relativa de las aristas observadas respecto al potencial de aristas.

Para un subgrafo \(H=(V_H,E_H)\) del grafo \(G=(V,E)\), la densidad se calcula como \[ \textsf{den(H)}=\frac{|E_H|}{|V_H|(|V_H|-1)/2}\,. \] En el caso de un digrafo el denominador debe ser \(|V_H|(|V_H|-1)\).

La densidad asume valores entre 0 y 1 y se puede interpretar como una medida de qué tan cerca se encuentra \(H\) de ser un clan.

Ejemplo: Interacciones sociales

# densidad
ecount(karate)/(vcount(karate)*(vcount(karate)-1)/2)
## [1] 0.1390374
edge_density(graph = karate)
## [1] 0.1390374
mean(Y[lower.tri(Y, diag = F)])
## [1] 0.3777778
mean(Y[upper.tri(Y, diag = F)])
## [1] 0.3777778
# ego networks
g_1  <- induced_subgraph(graph = karate, vids = neighborhood(graph = karate, order = 1, nodes = 1) [[1]])
g_34 <- induced_subgraph(graph = karate, vids = neighborhood(graph = karate, order = 1, nodes = 34)[[1]])
# densidades
edge_density(graph = g_1)
## [1] 0.25
edge_density(graph = g_34)
## [1] 0.2091503

Transitividad global

Una tripla está constituida por tres nodos que están conectados por dos (tripla abierta) o tres (tripla cerrada) aristas.

La transitividad (transitivity) de un grafo se cuantifica por medio del coeficiente de agrupamiento (clustering coeffitient) que se calcula como \[ \textsf{cl} (G) =\frac{\text{no. triplas cerradas}}{\text{no. triplas}} =\frac{3\times \text{no. triángulos}}{\text{no. triplas}} = \frac{3\tau_\triangle(G)}{\tau_3(G)}\,, \] donde \(\tau_\triangle(G)\) es el número de triángulos de \(G\) y \(\tau_3(G)\) es el número de triplas.

El coeficiente de agrupamiento es una medida de agrupamiento global que caracteriza la propensión con la que las triplas forman triángulos.

Ejemplo

# datos
h <- make_graph(edges = c(1,2,1,3,2,3,1,4), directed = F)
# visualización
set.seed(123)
plot(h, 
     vertex.size = 20, 
     vertex.color = 0, 
     vertex.label.color = "black", 
     edge.color = "blue4")

# número de triángulos por vértice
count_triangles(graph = h)
## [1] 1 1 1 0
# vértices que son parte de un triángulo
triangles(graph = h)
## + 3/4 vertices, from 81401b7:
## [1] 1 2 3
# conteos de estados triádicos
# Las clases no conexas no se consideran motivos y por eso aparecen como NA
# NA NA <camino_de_3_nodos> <triangulo>
# Clase 0: subgrafo vacío, NA
# Clase 1: un solo enlace, NA
# Clase 2: camino de longitud 2 o “V”
# Clase 3: triángulo
(mot <- motifs(graph = h, size = 3))
## [1] NA NA  2  1
# transitividad
3*mot[4]/(mot[3] + 3*mot[4])
## [1] 0.6
transitivity(graph = h, type = "global")
## [1] 0.6
  • \(\{1,2,3\}\) induce un triángulo, porque están las aristas \(1-2\), \(1-3\) y \(2-3\).

  • \(\{1,2,4\}\) induce un camino de longitud 2, porque están \(1-2\) y \(1-4\), pero no \(2-4\).

  • \(\{1,3,4\}\) induce otro camino de longitud 2, porque están \(1-3\) y \(1-4\), pero no \(3-4\).

  • \(\{2,3,4\}\) induce un subgrafo con una sola arista, \(2-3\), y el nodo \(4\) aislado, así que no es conexo y no cuenta como motivo.

Ejemplo

# datos
g <- make_graph(edges = c(1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,6,7,6,8,7,8,9,10,1,6,2,9,7,9), directed = F)
# visualización
set.seed(42)
plot(g, 
     vertex.size = 20, 
     vertex.color = 0, 
     vertex.label.color = "black",
     edge.color = "blue4")

# número de triángulos por vértice
count_triangles(graph = g)
##  [1] 6 6 6 6 6 1 1 1 0 0
# vértices que son parte de un triángulo
sort(triangles(graph = g))
## + 33/10 vertices, from 9ac4171:
##  [1] 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5 6 7 8
# conteos de estados triádicos
(mot <- motifs(graph = g, size = 3))
## [1] NA NA 15 11
# transitividad global
3*mot[4]/(mot[3] + 3*mot[4])
## [1] 0.6875
transitivity(graph = g, type = "global")
## [1] 0.6875

Transitividad local

El coeficiente de agrupamiento del vértice \(v\in V\) se define teniendo en cuenta la incidencia de \(v\) en las aristas que conforman las triplas: \[ \textsf{cl}(v) = \frac{\text{no. triplas cerradas que incluyen a $v$}}{k_v(k_v-1)/2}\,, \] donde \(k_v\) es el grado del nodo \(v\).

El coeficiente de agrupamiento de un vértice es una medida de agrupamiento local que cuantifica qué tan cerca están los vecinos del vértice de ser un clan.

Alternativamente, el coeficiente de agrupamiento global también se puede definir como el promedio de los coeficientes de agrupamiento locales de todos los vértices: \[ \textsf{cl} (G) = \frac{1}{|V|}\sum_{v\in V} \textsf{cl}(v)\,. \]

Ejemplo

# datos
g <- make_graph(edges = c(1,2,1,3,1,4,1,5,2,3,2,4,2,5,3,4,3,5,4,5,6,7,6,8,7,8,9,10,1,6,2,9,7,9), directed = F)
# visualización
set.seed(42)
plot(g, 
     vertex.size = 20, 
     vertex.color = 0, 
     vertex.label.color = "black", 
     edge.color = "blue4")

# intransitividad local del vértice 1
count_triangles(graph = g)
##  [1] 6 6 6 6 6 1 1 1 0 0
degree(graph = g)
##  [1] 5 5 4 4 4 3 3 2 3 1
6/(5*(5-1)/2)
## [1] 0.6
transitivity(graph = g, type = "local")
##  [1] 0.6000000 0.6000000 1.0000000 1.0000000 1.0000000 0.3333333 0.3333333
##  [8] 1.0000000 0.0000000       NaN
# transitividad global alternativa
mean(transitivity(graph = g, type = "local", vids = V(g)), na.rm = T)
## [1] 0.6518519

Ejemplo: Interacciones sociales

# transitividad
transitivity(graph = karate, type = "global")
## [1] 0.2556818
# intransitividad local
transitivity(karate, type = "local", vids = c(1, 34))
##     Mr Hi    John A 
## 0.1500000 0.1102941

Reciprocidad

Un concepto exclusivo de los dígrafos es la reciprocidad, i.e., la propensión con la que hay reciprocidad de aristas en la red.

Las frecuencias se pueden calcular respecto al número de díadas o de aristas: \[ \textsf{rec}(G) = \frac{\text{no. aristas reciprocas}}{\text{no. aristas}}\,, \] o alternativamente, \[ \textsf{rec}(G) = \frac{\text{no. diadas reciprocas}}{\text{no. diadas no reciprocas}}\,. \]

Ejemplo: Blogs de SIDA

# reciprocidad (aristas)
reciprocity(aidsblog, mode = "default")
## [1] 0.03278689
# reciprocidad (díadas)
reciprocity(aidsblog, mode = "ratio")
## [1] 0.01666667

Conectividad

Típicamente, una de las componentes conectadas de un grafo \(G=(V,E)\) domina a las demás en magnitud. Tal componente se denomina componente gigante (giant component).

En la práctica, la atención se restringe a la componente gigante para llevar a cabo tanto el análisis como el modelamiento.

Un grafo \(G=(V,E)\) se llama \(k\)-conectado por vértices si, para todo subconjunto de vértices \(X \subset V\) con \(|X| < k\), el subgrafo inducido por \(V \setminus X\) permanece conectado.

La conectividad nodal de un grafo \(G=(V,E)\) es el mayor entero \(k\) tal que \(G\) es \(k\)-conectado por vértices. Equivalentemente, corresponde al menor número de vértices cuya eliminación desconecta el grafo.

Un grafo \(G=(V,E)\) se llama \(k\)-conectado por aristas si, para todo subconjunto de aristas \(F \subset E\) con \(|F| < k\), el grafo \((V, E \setminus F)\) permanece conectado.

La conectividad por aristas de un grafo \(G=(V,E)\) es el mayor entero \(k\) tal que \(G\) es \(k\)-conectado por aristas. Equivalentemente, corresponde al menor número de aristas cuya eliminación desconecta el grafo.

Un vértice que al ser removido desconecta el grafo se denomina vértice de corte (cut vertex) o punto de articulación (articulation point).

La identificación de tales vértices proporciona una idea de dónde es vulnerable una red.

Ejemplo

# datos
f <- make_graph(edges = c(1,2,1,3,2,3,1,4,4,5), directed = F)
# visualización
set.seed(123)
plot(f, 
     vertex.size = 20, 
     vertex.color = 0, 
     vertex.label.color = "black", 
     edge.color = "blue4")

# red conectada?
is_connected(f)
## [1] TRUE
# conectividad nodal
vertex_connectivity(f)
## [1] 1
# conectividad por aristas
edge_connectivity(f)
## [1] 1
# puntos de articulación
articulation_points(f)
## + 2/5 vertices, from 8477bee:
## [1] 4 1

Ejemplo: Interacciones proteína-proteína

# red conectada?
is_connected(yeast)
## [1] FALSE
# componentes
componentes <- decompose(yeast)
length(componentes)
## [1] 92
table(sapply(X = componentes, FUN = vcount))
## 
##    2    3    4    5    6    7 2375 
##   63   13    5    6    1    3    1
# tamaño de la componte gigante
max(sapply(X = componentes, FUN = vcount))
## [1] 2375
max(sapply(X = componentes, FUN = vcount))/vcount(yeast)
## [1] 0.9075277
# componente gigante
yeast_gc <- decompose(yeast)[[1]]
# conectividad nodal
vertex_connectivity(yeast_gc)
## [1] 1
# conectivaidad por aristas
edge_connectivity(yeast_gc)
## [1] 1
# puntos de articulación
yeast_cv <- articulation_points(yeast_gc)
length(yeast_cv)
## [1] 350
length(yeast_cv)/vcount(yeast_gc)
## [1] 0.1473684

Se requiere la eliminación de un solo vértice o una sola arista para dividir el componente gigante en componentes adicionales.

Aproximadamente el 15% de los vértices son puntos de articulación.