This workbook applies social network analysis to my immediate family. Each node is an anonymized family role, and an edge represents a direct family or marital relationship. The network is undirected because these relationships are mutual rather than one-way interactions.
The network includes my immediate family and my wife’s immediate family: me, my wife and son, my parents and siblings, my father-in-law and mother-in-law, my wife’s two brothers, and two family dogs. Each dog is connected to Me, Wife, and Son to represent their shared household relationship.
family_edges <- data.frame(
from = c(
"Mom", "Mom", "Dad", "Mom", "Dad", "Mom", "Dad", "Mom", "Dad",
"Me", "Me", "Wife", "Me", "Me", "Me",
"Wife", "Wife", "Father in law", "Wife", "Wife",
"Father in law", "Mother in law", "Father in law", "Mother in law",
"Brother in law 1",
"Dog 1", "Dog 1", "Dog 1", "Dog 2", "Dog 2", "Dog 2"
),
to = c(
"Dad", "Me", "Me", "Brother", "Brother", "Sister 1", "Sister 1",
"Sister 2", "Sister 2", "Wife", "Son", "Son", "Brother", "Sister 1", "Sister 2",
"Father in law", "Mother in law", "Mother in law", "Brother in law 1", "Brother in law 2",
"Brother in law 1", "Brother in law 1", "Brother in law 2", "Brother in law 2",
"Brother in law 2",
"Me", "Wife", "Son", "Me", "Wife", "Son"
)
)
family_network <- graph_from_data_frame(family_edges, directed = FALSE)
vcount(family_network)
## [1] 14
ecount(family_network)
## [1] 31
role_colors <- c(
"Me" = "#F4A261", "Wife" = "#2A9D8F",
"Son" = "#8AC926", "Mom" = "#E76F51",
"Dad" = "#457B9D", "Brother" = "#6D597A",
"Sister 1" = "#B565A7", "Sister 2" = "#9C89B8",
"Father in law" = "#577590", "Mother in law" = "#F28482",
"Brother in law 1" = "#43AA8B", "Brother in law 2" = "#90BE6D",
"Dog 1" = "#F9C74F", "Dog 2" = "#F8961E"
)
role_label_colors <- c(
"Me" = "#1F2937", "Wife" = "white",
"Son" = "#1F2937", "Mom" = "white",
"Dad" = "white", "Brother" = "white",
"Sister 1" = "white", "Sister 2" = "#1F2937",
"Father in law" = "white", "Mother in law" = "#1F2937",
"Brother in law 1" = "white", "Brother in law 2" = "#1F2937",
"Dog 1" = "#1F2937", "Dog 2" = "#1F2937"
)
plot(
family_network,
layout = layout_with_fr(family_network),
vertex.color = role_colors[V(family_network)$name],
vertex.size = 30,
vertex.label.cex = 0.8,
vertex.label.color = role_label_colors[V(family_network)$name],
vertex.frame.color = "white",
edge.color = "#7A7A7A",
edge.width = 2,
main = "Family Network: Direct Family and Marital Relationships"
)
Figure 1. My anonymized family social network.
Degree centrality counts direct relationships. Betweenness centrality identifies people who lie on the most shortest paths between others. PageRank gives higher scores to people connected to others who also have many connections.
centrality <- data.frame(
person = V(family_network)$name,
degree = degree(family_network),
betweenness = round(betweenness(family_network, normalized = TRUE), 3),
closeness = round(closeness(family_network, normalized = TRUE), 3),
pagerank = round(page_rank(family_network)$vector, 3)
)
centrality <- centrality[order(-centrality$degree, -centrality$betweenness), ]
centrality_display <- centrality
names(centrality_display) <- c(
"Person", "Degree", "Betweenness", "Closeness", "PageRank"
)
print(centrality_display, row.names = FALSE)
## Person Degree Betweenness Closeness PageRank
## Me 9 0.530 0.765 0.137
## Wife 8 0.466 0.722 0.121
## Mom 5 0.013 0.520 0.081
## Dad 5 0.013 0.520 0.081
## Son 4 0.004 0.591 0.065
## Father in law 4 0.000 0.481 0.065
## Mother in law 4 0.000 0.481 0.065
## Brother in law 1 4 0.000 0.481 0.065
## Brother in law 2 4 0.000 0.481 0.065
## Dog 1 3 0.000 0.565 0.050
## Dog 2 3 0.000 0.565 0.050
## Brother 3 0.000 0.481 0.051
## Sister 1 3 0.000 0.481 0.051
## Sister 2 3 0.000 0.481 0.051
barplot(
centrality$degree,
names.arg = centrality$person,
las = 2,
col = "#4C78A8",
ylab = "Number of direct relationships",
main = "Degree Centrality"
)
Figure 2. Number of direct relationships by family member.
network_summary <- data.frame(
measure = c("Nodes", "Relationships", "Density", "Average path length",
"Global clustering coefficient"),
value = c(
vcount(family_network),
ecount(family_network),
round(edge_density(family_network), 3),
round(mean_distance(family_network), 3),
round(transitivity(family_network, type = "global"), 3)
)
)
knitr::kable(network_summary, caption = "Overall network measures")
| measure | value |
|---|---|
| Nodes | 14.000 |
| Relationships | 31.000 |
| Density | 0.341 |
| Average path length | 1.879 |
| Global clustering coefficient | 0.628 |
Louvain community detection groups nodes that are more closely connected to one another than to the rest of the network. In a small family network, these communities should be interpreted as relationship clusters, not as separate social groups with hard boundaries.
family_communities <- cluster_louvain(family_network)
membership(family_communities)
## Mom Dad Me Wife
## 1 1 1 2
## Father in law Mother in law Brother in law 1 Dog 1
## 2 2 2 3
## Dog 2 Brother Sister 1 Sister 2
## 3 1 1 1
## Son Brother in law 2
## 3 2
plot(
family_communities,
family_network,
layout = layout_with_fr(family_network),
vertex.size = 30,
vertex.label.cex = 0.8,
vertex.frame.color = "white",
edge.color = "#7A7A7A",
main = "Family Relationship Clusters"
)
Figure 3. Family relationship clusters from Louvain community detection.