Every like, friend request, tagged photo, and shared post leaves behind a trace of who is connected to whom. That trace is a network, and networks are one of the richest sources of customer insight available to marketing teams.
Two customers who share many mutual friends may be more likely to respond to the same campaign than two unrelated customers. A customer who sits at the center of many friendship triangles may be someone other people listen to. Two customers who are not directly connected but share several mutual contacts may represent a warm introduction opportunity.
This tutorial uses the igraph package in R to explore
the same core ideas found in large-scale graph tools such as Spark
GraphFrames. The analyses focus on practical marketing decisions:
A network, also called a graph, contains two basic elements:
Before analyzing a large social-media network, it helps to begin with a network that is familiar. The following example represents my own circle. It includes my immediate family, extended family on both sides, several cousins, and the professional and academic relationships I have developed at CSUCI.
Because individual relatives and CSUCI contacts are not named here, descriptive labels are used. These labels can be replaced with actual first names later without changing the network structure.
This family graph places me at the center of the network. My closest connections are my mom, my dad, and my brother Justin. My dad connects our immediate family to his brother, Uncle Todd. Uncle Todd is married to Aunt Laura, and their sons Josh and Danny are my cousins.
family_edges <- tribble(
~from, ~to,
# My direct family connections
"Britnay", "Mom",
"Britnay", "Dad",
"Britnay", "Justin",
"Britnay", "Aunt Laura",
"Britnay", "Uncle Todd",
"Britnay", "Josh",
"Britnay", "Danny",
# Family relationships
"Mom", "Dad",
"Mom", "Justin",
"Dad", "Justin",
"Dad", "Uncle Todd",
"Uncle Todd", "Aunt Laura",
"Uncle Todd", "Josh",
"Aunt Laura", "Josh",
"Uncle Todd", "Danny",
"Aunt Laura", "Danny",
"Josh", "Danny"
)
family_nodes <- tibble(
name = c(
"Britnay", "Mom", "Dad", "Justin",
"Aunt Laura", "Uncle Todd", "Josh", "Danny"
),
group = c(
"Me", "Immediate Family", "Immediate Family", "Immediate Family",
"Dad's Side", "Dad's Side", "Cousins", "Cousins"
)
)
family_graph <- graph_from_data_frame(
d = family_edges,
vertices = family_nodes,
directed = FALSE
)
# Manual coordinates keep Britnay in the center of the graph.
family_layout <- matrix(
c(
0.0, 0.0, # Britnay
-1.6, 1.2, # Mom
1.6, 1.2, # Dad
-1.7, -1.1, # Justin
2.8, -0.2, # Aunt Laura
2.8, 1.2, # Uncle Todd
1.7, -1.5, # Josh
3.2, -1.5 # Danny
),
ncol = 2,
byrow = TRUE,
dimnames = list(family_nodes$name, c("x", "y"))
)
plot(
family_graph,
layout = family_layout[V(family_graph)$name, ],
vertex.size = ifelse(V(family_graph)$name == "Britnay", 38, 27),
vertex.label.cex = 0.82,
vertex.label.dist = 0.3,
vertex.frame.color = "white",
edge.width = 1.6,
edge.curved = 0.08,
main = "My Family Connection Network"
)In this graph:
family_degree <- tibble(
person = V(family_graph)$name,
degree = as.numeric(degree(family_graph))
) %>%
arrange(desc(degree), person)
family_degree %>%
kable(caption = "Connections in My Family Network") %>%
kable_styling(
bootstrap_options = c("striped", "hover"),
full_width = FALSE
)| person | degree |
|---|---|
| Britnay | 7 |
| Uncle Todd | 5 |
| Aunt Laura | 4 |
| Dad | 4 |
| Danny | 4 |
| Josh | 4 |
| Justin | 3 |
| Mom | 3 |
Knowledge check: Why does Britnay have the highest degree in this graph?
Answer: Britnay is directly connected to every family member shown, so she has the greatest number of direct connections.
My CSUCI network includes relationships developed through work, graduate school, class projects, and campus collaboration. The generic labels below can be replaced with actual names or specific departments later.
csuci_edges <- tribble(
~from, ~to,
"Britnay", "Manager",
"Britnay", "Marketing Team",
"Britnay", "Recruitment Team",
"Britnay", "Admissions Team",
"Britnay", "Student Assistants",
"Britnay", "Program Directors",
"Britnay", "Faculty Partners",
"Britnay", "Graduate Professors",
"Britnay", "Class Teammates",
"Britnay", "Graduate Cohort",
"Britnay", "Campus Partners",
# Workplace collaboration
"Manager", "Marketing Team",
"Manager", "Recruitment Team",
"Marketing Team", "Student Assistants",
"Marketing Team", "Program Directors",
"Recruitment Team", "Admissions Team",
"Recruitment Team", "Program Directors",
"Admissions Team", "Student Assistants",
"Program Directors", "Faculty Partners",
"Faculty Partners", "Campus Partners",
# Graduate-program collaboration
"Graduate Professors", "Class Teammates",
"Graduate Professors", "Graduate Cohort",
"Class Teammates", "Graduate Cohort",
"Class Teammates", "Marketing Team",
"Graduate Cohort", "Campus Partners"
)
csuci_nodes <- tibble(name = unique(c(csuci_edges$from, csuci_edges$to))) %>%
mutate(
group = case_when(
name == "Britnay" ~ "Me",
name %in% c(
"Manager", "Marketing Team", "Recruitment Team", "Admissions Team",
"Student Assistants", "Program Directors", "Faculty Partners"
) ~ "CSUCI Workplace",
name %in% c("Graduate Professors", "Class Teammates", "Graduate Cohort") ~
"Graduate Program",
TRUE ~ "Campus Network"
)
)
csuci_graph <- graph_from_data_frame(
d = csuci_edges,
vertices = csuci_nodes,
directed = FALSE
)
set.seed(500)
plot(
csuci_graph,
layout = layout_with_fr(csuci_graph),
vertex.size = ifelse(V(csuci_graph)$name == "Britnay", 36, 28),
vertex.label.cex = 0.78,
vertex.label.dist = 0.4,
vertex.frame.color = "white",
edge.width = 1.7,
main = "My CSUCI Academic and Professional Network"
)The CSUCI graph demonstrates how one person may belong to multiple overlapping communities. My role connects workplace teams, academic relationships, and broader campus partners. This is important in social network analysis because people who connect otherwise separate groups often have high betweenness centrality and can help information travel across the organization.
csuci_centrality <- tibble(
connection = V(csuci_graph)$name,
degree = as.numeric(degree(csuci_graph)),
betweenness = as.numeric(
betweenness(csuci_graph, directed = FALSE, normalized = TRUE)
)
) %>%
arrange(desc(betweenness), desc(degree))
csuci_centrality %>%
kable(
caption = "Centrality in My CSUCI Network",
digits = 3
) %>%
kable_styling(
bootstrap_options = c("striped", "hover"),
full_width = FALSE
)| connection | degree | betweenness |
|---|---|---|
| Britnay | 11 | 0.567 |
| Marketing Team | 5 | 0.052 |
| Recruitment Team | 4 | 0.024 |
| Program Directors | 4 | 0.024 |
| Class Teammates | 4 | 0.018 |
| Graduate Cohort | 4 | 0.018 |
| Admissions Team | 3 | 0.009 |
| Faculty Partners | 3 | 0.009 |
| Student Assistants | 3 | 0.009 |
| Campus Partners | 3 | 0.009 |
| Manager | 3 | 0.006 |
| Graduate Professors | 3 | 0.000 |
Knowledge check: Why might a person with high betweenness centrality be important at CSUCI?
Answer: That person connects different teams or communities and can help information, resources, and collaboration move between them.
The final graph combines my family and CSUCI relationships. It illustrates that a person’s social network often contains multiple communities connected through one central individual.
combined_edges <- bind_rows(
family_edges %>% mutate(network = "Family"),
csuci_edges %>% mutate(network = "CSUCI")
) %>%
distinct(from, to, .keep_all = TRUE)
combined_nodes <- tibble(
name = unique(c(combined_edges$from, combined_edges$to))
) %>%
mutate(
community = case_when(
name == "Britnay" ~ "Me",
name %in% family_nodes$name ~ "Family",
TRUE ~ "CSUCI"
)
)
combined_graph <- graph_from_data_frame(
d = combined_edges,
vertices = combined_nodes,
directed = FALSE
)
set.seed(580)
plot(
combined_graph,
layout = layout_with_fr(combined_graph),
vertex.size = ifelse(V(combined_graph)$name == "Britnay", 38, 20),
vertex.label.cex = 0.62,
vertex.label.dist = 0.3,
vertex.frame.color = "white",
edge.width = 1.2,
main = "My Combined Family and CSUCI Circle"
)In this combined graph, I function as the main bridge between two major communities. The family network represents personal support and long-term relationships, while the CSUCI network represents academic, professional, and collaborative relationships. Together, they demonstrate how network analysis can reveal the different roles a person occupies across social settings.
The Stanford Network Analysis Project’s Facebook Circles dataset is an anonymized snapshot of Facebook friendships. It contains users as vertices, friendship links as edges, and user attributes such as birthday, hometown, employer, and school.
For this tutorial, we simulate a smaller network that has the same general structure:
id, birthday,
hometown, employer_id, and
school_idsrc and dst,
representing friendship connectionsset.seed(580)
n_users <- 150
vertices <- tibble(
id = 1:n_users,
birthday = sample(
seq(as.Date("1985-01-01"), as.Date("2005-12-31"), by = "day"),
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 = "First Five Rows of the Simulated User Table") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| id | birthday | hometown | employer_id | school_id |
|---|---|---|---|---|
| 1 | 1989-08-29 | City B | 4 | 5 |
| 2 | 1991-01-04 | City B | 12 | 5 |
| 3 | 1998-04-19 | City A | 1 | 4 |
| 4 | 1986-02-27 | City H | 10 | 9 |
| 5 | 1988-04-09 | City H | 5 | 2 |
Each row represents one user. The attributes allow marketers to examine questions such as whether connected users share a school, employer, hometown, or birthday.
A Barabasi-Albert preferential-attachment graph creates a realistic hub pattern in which a small number of users are highly connected while most users have fewer connections.
set.seed(580)
g_sim <- sample_pa(
n = n_users,
power = 1.1,
m = 3,
directed = FALSE
)
edges <- as_data_frame(g_sim, what = "edges") %>%
transmute(
src = as.integer(from),
dst = as.integer(to)
)
edges %>%
slice_head(n = 5) %>%
kable(caption = "First Five Rows of the Simulated Friendship Table") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| src | dst |
|---|---|
| 1 | 2 |
| 1 | 3 |
| 2 | 3 |
| 1 | 4 |
| 2 | 4 |
Knowledge check: Which table stores friendship relationships?
Answer: The edge table.
The graph_from_data_frame() function combines the edge
table and vertex table into one graph object.
## IGRAPH 9a45c36 UN-- 150 444 --
## + attr: name (v/c), birthday (v/n), hometown (v/c), employer_id (v/n),
## | school_id (v/n)
## + edges from 9a45c36 (vertex names):
## [1] 1 --2 1 --3 2 --3 1 --4 2 --4 3 --4 3 --5 1 --5 4 --5 2 --6
## [11] 3 --6 1 --6 1 --7 2 --7 3 --7 4 --8 2 --8 6 --8 4 --9 1 --9
## [21] 3 --9 3 --10 2 --10 1 --10 6 --11 1 --11 3 --11 11--12 1 --12 6 --12
## [31] 6 --13 12--13 10--13 2 --14 11--14 3 --14 4 --15 8 --15 3 --15 3 --16
## [41] 6 --16 11--16 13--17 10--17 2 --17 4 --18 6 --18 5 --18 9 --19 1 --19
## [51] 2 --19 18--20 11--20 1 --20 6 --21 1 --21 10--21 10--22 3 --22 6 --22
## [61] 17--23 11--23 19--23 13--24 10--24 2 --24 6 --25 1 --25 23--25 1 --26
## + ... omitted several edges
A triplet displays an edge together with the attributes of both users connected by that edge.
triplets <- as_data_frame(fb_graph, what = "edges") %>%
transmute(
from = as.integer(from),
to = as.integer(to)
) %>%
left_join(vertices, by = c("from" = "id")) %>%
rename(
a_birthday = birthday,
a_hometown = hometown,
a_employer_id = employer_id,
a_school_id = school_id
) %>%
left_join(vertices, by = c("to" = "id")) %>%
rename(
b_birthday = birthday,
b_hometown = hometown,
b_employer_id = employer_id,
b_school_id = school_id
)
triplets %>%
slice_head(n = 3) %>%
kable(caption = "Sample Triplets: An Edge and Both Users' Attributes") %>%
kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE,
font_size = 12
)| from | to | a_birthday | a_hometown | a_employer_id | a_school_id | b_birthday | b_hometown | b_employer_id | b_school_id |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 1989-08-29 | City B | 4 | 5 | 1991-01-04 | City B | 12 | 5 |
| 1 | 3 | 1989-08-29 | City B | 4 | 5 | 1998-04-19 | City A | 1 | 4 |
| 2 | 3 | 1991-01-04 | City B | 12 | 5 | 1998-04-19 | City A | 1 | 4 |
A shared birthday is a simple personalization opportunity for a loyalty campaign or a celebrate-together promotion.
same_birthday <- triplets %>%
filter(a_birthday == b_birthday) %>%
transmute(
user_a = from,
user_b = to,
shared_birthday = a_birthday
)
if (nrow(same_birthday) == 0) {
tibble(result = "No directly connected users share the exact same birthday in this simulation.") %>%
kable(caption = "Friend Pairs Who Share a Birthday") %>%
kable_styling(full_width = FALSE)
} else {
same_birthday %>%
slice_head(n = 5) %>%
kable(caption = "Friend Pairs Who Share a Birthday") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
}| result |
|---|
| No directly connected users share the exact same birthday in this simulation. |
Marketing takeaway: A loyalty program could offer a shared discount to connected customers who celebrate a birthday on the same date or in the same month.
A triangle consists of three users who are all mutually connected. Users in many triangles may belong to cohesive communities where recommendations spread through trusted relationships.
triangle_counts <- tibble(
id = as.integer(V(fb_graph)$name),
triangle_count = count_triangles(fb_graph)
) %>%
left_join(vertices, by = "id") %>%
arrange(desc(triangle_count))
triangle_counts %>%
slice_head(n = 10) %>%
select(id, hometown, employer_id, school_id, triangle_count) %>%
kable(caption = "Users Embedded in the Most Friendship Triangles") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| id | hometown | employer_id | school_id | triangle_count |
|---|---|---|---|---|
| 1 | City B | 4 | 5 | 50 |
| 3 | City A | 1 | 4 | 36 |
| 2 | City B | 12 | 5 | 35 |
| 6 | City E | 6 | 1 | 29 |
| 4 | City H | 10 | 9 | 15 |
| 11 | City F | 2 | 4 | 14 |
| 10 | City C | 5 | 2 | 13 |
| 21 | City C | 5 | 1 | 9 |
| 16 | City A | 6 | 2 | 7 |
| 29 | City G | 4 | 2 | 7 |
triangle_counts %>%
slice_head(n = 10) %>%
mutate(id = reorder(as.factor(id), triangle_count)) %>%
ggplot(aes(x = id, y = triangle_count)) +
geom_col() +
coord_flip() +
labs(
title = "Top 10 Users by Friendship Triangle Count",
x = "User ID",
y = "Number of Triangles"
) +
theme_minimal()Marketing takeaway: Triangle-dense groups are strong candidates for referral campaigns, group discounts, ambassador programs, and community-building initiatives.
Knowledge check: What does a high triangle count usually indicate?
Answer: The user is embedded in many tightly connected groups.
A friend-of-friend recommendation identifies two users who are not directly connected but share at least one mutual friend. We strengthen the recommendation by also requiring the two users to share the same school.
# Calculate shortest-path distances between all users.
distance_matrix <- distances(fb_graph)
# Pairs at distance 2 are friends-of-friends but are not direct friends.
fof_pairs <- which(distance_matrix == 2, arr.ind = TRUE) %>%
as.data.frame() %>%
as_tibble() %>%
transmute(
user_a = as.integer(rownames(distance_matrix)[row]),
user_b = as.integer(colnames(distance_matrix)[col])
) %>%
filter(user_a < user_b) %>%
distinct()
friends_of_friends <- fof_pairs %>%
left_join(
vertices %>% select(id, school_id, hometown),
by = c("user_a" = "id")
) %>%
rename(
school_id_a = school_id,
hometown_a = hometown
) %>%
left_join(
vertices %>% select(id, school_id, hometown),
by = c("user_b" = "id")
) %>%
rename(
school_id_b = school_id,
hometown_b = hometown
) %>%
filter(school_id_a == school_id_b)
friends_of_friends %>%
slice_head(n = 10) %>%
kable(caption = "Friend-of-Friend Pairs Who Attended the Same School") %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| user_a | user_b | school_id_a | hometown_a | school_id_b | hometown_b |
|---|---|---|---|---|---|
| 5 | 9 | 2 | City H | 2 | City B |
| 5 | 10 | 2 | City H | 2 | City C |
| 9 | 10 | 2 | City B | 2 | City C |
| 3 | 12 | 4 | City A | 4 | City H |
| 1 | 13 | 5 | City B | 5 | City D |
| 2 | 13 | 5 | City B | 5 | City D |
| 5 | 14 | 2 | City H | 2 | City B |
| 9 | 14 | 2 | City B | 2 | City B |
| 10 | 14 | 2 | City C | 2 | City B |
| 5 | 16 | 2 | City H | 2 | City A |
Marketing takeaway: Mutual connections combined with a shared school, employer, or hometown can power warmer and more relevant recommendations for alumni networks, event platforms, and professional communities.
PageRank measures not only how many connections a person has, but also how well connected those connections are.
pr <- page_rank(fb_graph, damping = 0.85)$vector
influencers <- tibble(
id = as.integer(names(pr)),
pagerank = as.numeric(pr),
degree = as.numeric(degree(fb_graph, v = names(pr)))
) %>%
left_join(vertices, by = "id") %>%
arrange(desc(pagerank))
influencers %>%
slice_head(n = 10) %>%
select(id, hometown, employer_id, school_id, degree, pagerank) %>%
kable(
caption = "Top 10 Potential Influencers by PageRank",
digits = 4
) %>%
kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)| id | hometown | employer_id | school_id | degree | pagerank |
|---|---|---|---|---|---|
| 1 | City B | 4 | 5 | 39 | 0.0385 |
| 2 | City B | 12 | 5 | 35 | 0.0350 |
| 3 | City A | 1 | 4 | 28 | 0.0275 |
| 6 | City E | 6 | 1 | 25 | 0.0244 |
| 11 | City F | 2 | 4 | 23 | 0.0235 |
| 21 | City C | 5 | 1 | 17 | 0.0174 |
| 10 | City C | 5 | 2 | 17 | 0.0172 |
| 18 | City B | 11 | 1 | 16 | 0.0166 |
| 4 | City H | 10 | 9 | 16 | 0.0161 |
| 19 | City D | 11 | 3 | 14 | 0.0152 |
influencers %>%
ggplot(aes(x = degree, y = pagerank)) +
geom_point(alpha = 0.7) +
geom_smooth(method = "lm", se = FALSE) +
labs(
title = "Degree and PageRank Are Related but Not Identical",
x = "Number of Direct Connections",
y = "PageRank Score"
) +
theme_minimal()Marketing takeaway: PageRank can help marketers shortlist brand ambassadors whose influence extends through other well-connected users rather than relying only on follower count.
Knowledge check: Why does PageRank rank a user highly?
Answer: The user is connected to other highly connected users.
PageRank was originally designed for websites. Each hyperlink acts like a vote from one page to another. Because hyperlinks are directional, a website link network must be modeled as a directed graph.
The following example models an illustrative internal-link network for California State University Channel Islands (CSUCI). It shows how major university pages can pass authority to admissions, academic programs, Extended University, and individual program pages.
csuci_links <- tribble(
~from, ~to, ~url_to,
"CSUCI Home", "About CSUCI", "csuci.edu/about/",
"CSUCI Home", "Academics", "csuci.edu/academics/",
"CSUCI Home", "Admissions", "csuci.edu/admissions/",
"CSUCI Home", "Financial Aid", "csuci.edu/financialaid/",
"CSUCI Home", "Library", "library.csuci.edu/",
"CSUCI Home", "News", "news.csuci.edu/",
"CSUCI Home", "Extended University", "ext.csuci.edu/",
"Admissions", "CSUCI Home", "csuci.edu/",
"Admissions", "Academics", "csuci.edu/academics/",
"Admissions", "Financial Aid", "csuci.edu/financialaid/",
"Admissions", "Extended University", "ext.csuci.edu/",
"Admissions", "Online Programs", "ext.csuci.edu/programs/online-programs.htm",
"Extended University", "CSUCI Home", "csuci.edu/",
"Extended University", "Admissions", "csuci.edu/admissions/",
"Extended University", "Online Programs", "ext.csuci.edu/programs/online-programs.htm",
"Extended University", "Graduate Programs", "ext.csuci.edu/programs/graduate-programs.htm",
"Extended University", "Degree Completion", "ext.csuci.edu/programs/degree-completion.htm",
"Extended University", "MBA Program", "ext.csuci.edu/programs/mba/",
"Online Programs", "MBA Program", "ext.csuci.edu/programs/mba/",
"Graduate Programs", "MBA Program", "ext.csuci.edu/programs/mba/",
"Degree Completion", "Online Programs", "ext.csuci.edu/programs/online-programs.htm"
)
csuci_graph <- graph_from_data_frame(
csuci_links %>% select(from, to),
directed = TRUE
)
csuci_pr <- page_rank(csuci_graph, damping = 0.85)$vector
csuci_rank <- tibble(
page = names(csuci_pr),
pagerank = as.numeric(csuci_pr)
) %>%
arrange(desc(pagerank))
csuci_rank %>%
kable(
caption = "Illustrative CSUCI Website Pages Ranked by PageRank",
digits = 4
) %>%
kable_styling(
bootstrap_options = c("striped", "hover"),
full_width = FALSE
)| page | pagerank |
|---|---|
| MBA Program | 0.2184 |
| Online Programs | 0.1245 |
| CSUCI Home | 0.0727 |
| Extended University | 0.0714 |
| Academics | 0.0714 |
| Financial Aid | 0.0714 |
| Admissions | 0.0697 |
| Graduate Programs | 0.0609 |
| Degree Completion | 0.0609 |
| About CSUCI | 0.0596 |
| Library | 0.0596 |
| News | 0.0596 |
V(csuci_graph)$pagerank <- csuci_pr[V(csuci_graph)$name]
set.seed(580)
plot(
csuci_graph,
layout = layout_with_fr(csuci_graph),
vertex.size = 15 + rescale(V(csuci_graph)$pagerank, to = c(0, 35)),
vertex.color = col_numeric("Blues", domain = NULL)(V(csuci_graph)$pagerank),
vertex.label.color = "black",
vertex.label.cex = 0.75,
vertex.frame.color = "white",
edge.arrow.size = 0.4,
edge.color = "grey60",
main = "Illustrative CSUCI Internal-Link Network"
)Pages linked by several important source pages receive more authority. In this example, pages such as Admissions and Extended University act as hubs because they connect users to several academic and enrollment-related pages.
Marketing takeaway: CSUCI can strengthen the visibility of priority program pages by linking to them from high-authority pages such as the university homepage, Admissions, Extended University, relevant academic departments, and university news stories.
The networkD3 package converts the CSUCI website graph
into an interactive force-directed network. Users can drag, zoom, and
explore the graph in the knitted HTML file.
nodes_d3 <- tibble(
name = V(csuci_graph)$name,
pagerank = V(csuci_graph)$pagerank,
group = 1
)
links_d3 <- as_data_frame(csuci_graph, what = "edges") %>%
transmute(
source = match(from, nodes_d3$name) - 1,
target = match(to, nodes_d3$name) - 1,
value = 1
)
forceNetwork(
Links = as.data.frame(links_d3),
Nodes = as.data.frame(nodes_d3),
Source = "source",
Target = "target",
Value = "value",
NodeID = "name",
Group = "group",
Nodesize = "pagerank",
radiusCalculation = htmlwidgets::JS("Math.sqrt(d.nodesize) * 40 + 6"),
linkDistance = 130,
opacity = 0.9,
zoom = TRUE,
arrows = TRUE,
fontSize = 14,
bounded = TRUE
)Knowledge check: What does
networkD3add?
Answer: It lets the user drag, zoom, and explore the CSUCI network interactively in a browser.
Shared attributes can support personalized promotions, while tightly connected friend groups can be targeted with group-oriented campaigns.
Mutual connections, shared schools, and shared employers can support attendee matchmaking, alumni engagement, and professional introductions.
PageRank can identify users whose influence is reinforced by the importance of their connections, rather than by follower count alone.
Dense clusters reveal communities that already exist. Marketers can support these communities through relevant content, events, and referral programs.
Potential business applications include:
Social network analysis turns a collection of relationships into
actionable marketing information. In this tutorial, R and
igraph were used to examine shared customer attributes,
friendship triangles, friends of friends, influential users, and website
authority.
These techniques support four practical marketing decisions:
Final knowledge check: Which method is most similar to LinkedIn’s “People You May Know”?
Answer: Friend-of-friend analysis.
Bostock, M., Ogievetsky, V., & Heer, J. (2011). D3: Data-driven documents. IEEE Transactions on Visualization and Computer Graphics, 17(12), 2301-2309.
California State University, Bakersfield. (2026). Home, admissions, and College of Business and Public Administration webpages. Accessed July 23, 2026.
Csardi, G., & Nepusz, T. (2006). The igraph software package for complex network research. InterJournal, Complex Systems, 1695.
Gandrud, C., Allaire, J. J., & Russell, K. (n.d.). networkD3: D3 JavaScript network graphs from R [R package].
Leskovec, J., & Krevl, A. (2014). SNAP datasets: Stanford Large Network Dataset Collection. Stanford Network Analysis Project.
Page, L., Brin, S., Motwani, R., & Winograd, T. (1999). The PageRank citation ranking: Bringing order to the web. Stanford InfoLab.
Scaibu. (2024, November 18). Facebook Circles: A deeper dive into social network analysis using GraphFrames. Medium.
Xu, Z. “Jimmy.” (2018). Social network analysis using R. RPubs.