Instagram Network Analysis

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
)

Interpretation

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.

Quiz: Highest-Degree Vertex

In g_ig, which vertex has the highest degree (the most direct connections)?



Step 1: Simulating the vertices (user) table

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")
Instagram Vertex Table
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

Step 2: Simulating the edges (friendship) table

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")
Instagram Edge Table
src dst
1 2
2 3
1 3
1 4
1 5
Which table stores the connections (interaction ties) between users?


Step 3: Building the graph

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)
Sample ‘triplets’: an edge plus both users’ attributes
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

Step 4: Graph analysis — algorithms and marketing use cases

1. Finding users with the same hometown

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")
Pairs of users who share the same hometown
from to shared_hometown
1 2 City C

2. Counting friendship triangles

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")
Users embedded in the most friendship triangles
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"
)

A high triangle count for a user most likely indicates…


3. Friends of friends: expanding social circles

Friends-of-friends (FoF) finds pairs of users who share a mutual friend but aren’t directly connected yet — the same logic LinkedIn uses for “People You May Know.”

# Step 1: Extract edges (numeric ids)
edge_list <- as_data_frame(ig_graph, what = "edges") %>%
  transmute(
    a = as.integer(from),
    b = as.integer(to)
  )

# Step 2: Build adjacency list (undirected)
adj <- edge_list %>%
  bind_rows(edge_list %>% transmute(a = b, b = a)) %>%
  group_by(a) %>%
  summarise(neighbors = list(b), .groups = "drop")

# Step 3: Generate FoF pairs using combn(), but convert to a tibble manually
fof_raw <- adj %>%
  rowwise() %>%
  mutate(pairs = list({
    if (length(neighbors) < 2) {
      tibble(a = integer(), c = integer())
    } else {
      m <- combn(neighbors, 2)
      tibble(a = m[1, ], c = m[2, ])
    }
  })) %>%
  ungroup() %>%
  select(pairs) %>%
  unnest(pairs)

# Step 4: Remove existing edges (undirected)
fof_clean <- fof_raw %>%
  anti_join(edge_list, by = c("a" = "a", "c" = "b")) %>%
  anti_join(edge_list, by = c("a" = "b", "c" = "a")) %>%
  distinct()

# Step 5: Join school_id for both endpoints
fof_school <- fof_clean %>%
  left_join(vertices %>% select(id, school_id), by = c("a" = "id")) %>%
  rename(school_id_a = school_id) %>%
  left_join(vertices %>% select(id, school_id), by = c("c" = "id")) %>%
  rename(school_id_c = school_id) %>%
  filter(school_id_a == school_id_c)

fof_school %>%
  slice_head(n = 5) %>%
  kable(caption = "Friends-of-friends pairs who also attended the same school") %>%
  kable_styling(latex_options = "striped")
Friends-of-friends pairs who also attended the same school
a c school_id_a school_id_c
3 5 4 4
3 3 4 4
5 5 4 4
6 6 2 2

4. Identifying influencers using PageRank

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")
Top 5 most influential users by PageRank
name pagerank
1 0.3323
2 0.1440
4 0.1028
6 0.1028
5 0.0999
PageRank ranks a user highly mainly because of…


Visualizations

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)"
)

Interpretation

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).

PageRank Influence Plot

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
)

Interpretation

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)

Which technique is the closest analogue to LinkedIn’s ‘People You May Know’?



References

  • Backstrom, L., & Kleinberg, J. (2011). Network Structure and Predictive Models for Link Prediction in Social Networks. ACM WWW.
  • Csardi, G., & Nepusz, T. (2006). The igraph software package for complex network research. InterJournal, Complex Systems, 1695.
  • Domingos, P. (2005). Mining Social Networks for Viral Marketing. IEEE Intelligent Systems.
  • Gandrud, C., Allaire, J. J., & Russell, K. networkD3: D3 JavaScript Network Graphs from R.
  • Leskovec, J., Rajaraman, A., & Ullman, J. (2020). Mining of Massive Datasets. Cambridge University Press.
  • Newman, M. E. J. (2010). Networks: An Introduction. Oxford University Press.
  • Page, L., Brin, S., Motwani, R., & Winograd, T. (1999). The PageRank Citation Ranking: Bringing Order to the Web. Stanford InfoLab.
  • Wasserman, S., & Faust, K. (1994). Social Network Analysis: Methods and Applications. Cambridge University Press.
  • Xu, Z. “Jimmy” (2018). Social network analysis using R. RPubs. https://rpubs.com/utjimmyx/network1