I mapped a small network based on my Instagram interactions, with all names anonymized. The node Me represents my own account. Edges represent meaningful interactions such as DMs, collaborations, shared group chats, or frequent engagement.
# Instagram anonymized network
g_ig <- graph_from_literal(
Me - CloseFriend1 - CloseFriend2,
Me - MutualMusicA,
Me - MutualMusicB,
Me - CollabPartner1,
CollabPartner1 - MutualMusicA,
CloseFriend1 - MutualMusicB,
Me - FollowerX,
Me - FollowerY
)
plot(
g_ig,
layout = layout_with_fr,
vertex.size = 25,
vertex.label.cex = 0.9
)
In this network, Me is the highest‑degree node, which is expected since all alters connect directly to the ego. The alters cluster into categories: close friends, music‑related mutuals, collaborators, and general followers. A few alters also connect to each other, reflecting shared group chats or overlapping social circles.
set.seed(580)
n_users <- 8 # Instagram network size
vertices <- tibble(
id = 1:n_users,
account_type = sample(
c("close_friend", "mutual", "collaborator", "follower"),
n_users, replace = TRUE
),
hometown = sample(paste("City", LETTERS[1:8]), n_users, replace = TRUE),
employer_id = sample(1:12, n_users, replace = TRUE),
school_id = sample(1:10, n_users, replace = TRUE)
)
vertices %>%
slice_head(n = 5) %>%
kable(caption = "Instagram Vertex Table") %>%
kable_styling(latex_options = "striped")
| id | account_type | hometown | employer_id | school_id |
|---|---|---|---|---|
| 1 | mutual | City C | 10 | 5 |
| 2 | collaborator | City C | 1 | 6 |
| 3 | close_friend | City B | 12 | 4 |
| 4 | collaborator | City G | 8 | 7 |
| 5 | collaborator | City D | 2 | 4 |
edges <- tribble(
~src, ~dst,
1, 2, # Me - CloseFriend1
2, 3, # CloseFriend1 - CloseFriend2
1, 3, # Me - CloseFriend2
1, 4, # Me - MutualMusicA
1, 5, # Me - MutualMusicB
1, 6, # Me - CollabPartner1
6, 4, # CollabPartner1 - MutualMusicA
2, 5, # CloseFriend1 - MutualMusicB
1, 7, # Me - FollowerX
1, 8 # Me - FollowerY
)
edges %>%
slice_head(n = 5) %>%
kable(caption = "Instagram Edge Table") %>%
kable_styling(latex_options = "striped")
| src | dst |
|---|---|
| 1 | 2 |
| 2 | 3 |
| 1 | 3 |
| 1 | 4 |
| 1 | 5 |
ig_graph <- graph_from_data_frame(
d = edges,
vertices = vertices,
directed = FALSE
)
ig_graph
## IGRAPH c28e3a3 UN-- 8 10 --
## + attr: name (v/c), account_type (v/c), hometown (v/c), employer_id
## | (v/n), school_id (v/n)
## + edges from c28e3a3 (vertex names):
## [1] 1--2 2--3 1--3 1--4 1--5 1--6 4--6 2--5 1--7 1--8
# Extract edges from igraph object
edge_df <- as_data_frame(ig_graph, what = "edges") %>%
mutate(
from = as.integer(from),
to = as.integer(to)
)
# Join attributes for the 'from' endpoint
triplets <- edge_df %>%
left_join(vertices, by = c("from" = "id")) %>%
rename_with(~ paste0("a_", .),
.cols = c(account_type, hometown, employer_id, school_id)) %>%
# Join attributes for the 'to' endpoint
left_join(vertices, by = c("to" = "id")) %>%
rename_with(~ paste0("b_", .),
.cols = c(account_type, hometown, employer_id, school_id))
triplets %>%
slice_head(n = 3) %>%
kable(caption = "Sample 'triplets': an edge plus both users' attributes") %>%
kable_styling(latex_options = "striped", font_size = 9)
| from | to | a_account_type | a_hometown | a_employer_id | a_school_id | b_account_type | b_hometown | b_employer_id | b_school_id |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | mutual | City C | 10 | 5 | collaborator | City C | 1 | 6 |
| 2 | 3 | collaborator | City C | 1 | 6 | close_friend | City B | 12 | 4 |
| 1 | 3 | mutual | City C | 10 | 5 | close_friend | City B | 12 | 4 |
A shared hometown is a lightweight, low-cost personalization hook — useful for local events or “same city” campaigns.
# Extract edges from graph (igraph already uses 'from' and 'to')
edge_df <- as_data_frame(ig_graph, what = "edges") %>%
mutate(
from = as.integer(from),
to = as.integer(to)
)
same_hometown <- edge_df %>%
left_join(vertices, by = c("from" = "id")) %>%
rename_with(~ paste0("a_", .),
.cols = c(account_type, hometown, employer_id, school_id)) %>%
left_join(vertices, by = c("to" = "id")) %>%
rename_with(~ paste0("b_", .),
.cols = c(account_type, hometown, employer_id, school_id)) %>%
filter(a_hometown == b_hometown) %>%
select(from, to, shared_hometown = a_hometown)
same_hometown %>%
slice_head(n = 5) %>%
kable(caption = "Pairs of users who share the same hometown") %>%
kable_styling(latex_options = "striped")
| from | to | shared_hometown |
|---|---|---|
| 1 | 2 | City C |
triangle_counts <- tibble(
name = V(ig_graph)$name,
triangle_count = count_triangles(ig_graph)
)
triangle_counts %>%
arrange(desc(triangle_count)) %>%
slice_head(n = 5) %>%
kable(caption = "Users embedded in the most friendship triangles") %>%
kable_styling(latex_options = "striped")
| name | triangle_count |
|---|---|
| 1 | 3 |
| 2 | 2 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
# Build a subgraph of same-hometown edges
same_hometown_edges <- same_hometown %>%
select(from, to)
g_same <- graph_from_data_frame(same_hometown_edges, directed = FALSE)
plot(
g_same,
layout = layout_with_fr,
vertex.size = 25,
vertex.label.cex = 0.9,
main = "Users Who Share the Same Hometown"
)
PageRank scores each user by how well-connected their friends are, not just how many friends they have.
# PageRank scores for each user
pr <- page_rank(ig_graph, damping = 0.85)$vector
influencers <- tibble(
name = names(pr),
pagerank = pr
) %>%
arrange(desc(pagerank))
influencers %>%
slice_head(n = 5) %>%
kable(caption = "Top 5 most influential users by PageRank", digits = 4) %>%
kable_styling(latex_options = "striped")
| name | pagerank |
|---|---|
| 1 | 0.3323 |
| 2 | 0.1440 |
| 4 | 0.1028 |
| 6 | 0.1028 |
| 5 | 0.0999 |
deg <- degree(ig_graph)
hist(
deg,
breaks = seq(min(deg)-0.5, max(deg)+0.5, 1),
col = "steelblue",
main = "Degree Distribution of My Instagram Network",
xlab = "Degree (Number of Direct Connections)"
)
The degree distribution shows a classic network shape: one high‑degree node (me) and a set of low‑degree alters. This reflects the structure described earlier — “Me is the highest‑degree node, which is expected since all alters connect directly to the ego.” Most nodes have degree 1–2, meaning they interact with me but not broadly with each other. This is typical of small personal networks where the ego is the main bridge between otherwise disconnected groups (Backstrom, 2011).
pr <- page_rank(ig_graph)$vector
barplot(
pr,
col = "darkorange",
main = "PageRank Scores of Users",
xlab = "User",
ylab = "PageRank",
names.arg = names(pr),
las = 2
)
PageRank surfaces the users who matter not because they have many connections, but because they are connected to well‑connected users. As the document explains, “PageRank ranks a user highly mainly because of being connected to other highly‑connected users.” In my network, the top‑ranked alters are the ones who bridge multiple subgroups — typically collaborators or mutuals who also connect to others beyond me. This aligns with how influencer identification works in marketing analytics (Page, 1999)