I have a dataset for a campaigns workflow. Each campaign can send multiple communication elements com_elm to recipients recipient_id. I want to measure the overlap of recipients between those different campaigns.
I experimented with various ways of achieving this goal and found a solution. However the journey left me with some questions, which I am looking for answers to and which I will post at the bottom of this questions.
Here is the dataset:
datv <- structure(list(campaign = c("campaign_x", "campaign_x", "campaign_x",
"campaign_x", "campaign_x", "campaign_x", "campaign_x", "campaign_x",
"campaign_x", "campaign_x", "campaign_x", "campaign_x", "campaign_x",
"campaign_x", "campaign_x", "campaign_x", "campaign_x", "campaign_x",
"campaign_x", "campaign_x", "campaign_x", "campaign_x", "campaign_x",
"campaign_x", "campaign_x", "campaign_x", "campaign_x", "campaign_x",
"campaign_x", "campaign_x", "campaign_y", "campaign_y", "campaign_y",
"campaign_y", "campaign_y", "campaign_y", "campaign_y", "campaign_y",
"campaign_y", "campaign_y", "campaign_y", "campaign_y", "campaign_y",
"campaign_y", "campaign_y", "campaign_y", "campaign_y", "campaign_y",
"campaign_y", "campaign_y", "campaign_y", "campaign_y", "campaign_y",
"campaign_y", "campaign_y", "campaign_y", "campaign_y", "campaign_y",
"campaign_y", "campaign_y", "campaign_z", "campaign_z", "campaign_z",
"campaign_z", "campaign_z", "campaign_z", "campaign_z", "campaign_z",
"campaign_z", "campaign_z", "campaign_z", "campaign_z", "campaign_z",
"campaign_z", "campaign_z", "campaign_z", "campaign_z", "campaign_z",
"campaign_z", "campaign_z", "campaign_z", "campaign_z", "campaign_z",
"campaign_z", "campaign_z", "campaign_z", "campaign_z", "campaign_z",
"campaign_z", "campaign_z"), com_elm = c("campaign_x_C3", "campaign_x_B1",
"campaign_x_B2", "campaign_x_C3", "campaign_x_C3", "campaign_x_B1",
"campaign_x_B2", "campaign_x_C3", "campaign_x_C3", "campaign_x_B1",
"campaign_x_B2", "campaign_x_C3", "campaign_x_B1", "campaign_x_C3",
"campaign_x_B1", "campaign_x_A1", "campaign_x_C3", "campaign_x_B1",
"campaign_x_B1", "campaign_x_C3", "campaign_x_B1", "campaign_x_A1",
"campaign_x_C3", "campaign_x_C3", "campaign_x_B1", "campaign_x_B2",
"campaign_x_C3", "campaign_x_B1", "campaign_x_C3", "campaign_x_C3",
"campaign_y_C3", "campaign_y_B1", "campaign_y_B2", "campaign_y_C3",
"campaign_y_C3", "campaign_y_B1", "campaign_y_B2", "campaign_y_C3",
"campaign_y_C3", "campaign_y_B1", "campaign_y_B2", "campaign_y_C3",
"campaign_y_B1", "campaign_y_C3", "campaign_y_B1", "campaign_y_A1",
"campaign_y_C3", "campaign_y_B1", "campaign_y_B1", "campaign_y_C3",
"campaign_y_B1", "campaign_y_A1", "campaign_y_C3", "campaign_y_C3",
"campaign_y_B1", "campaign_y_B2", "campaign_y_C3", "campaign_y_B1",
"campaign_y_C3", "campaign_y_C3", "campaign_z_C3", "campaign_z_B1",
"campaign_z_B2", "campaign_z_C3", "campaign_z_C3", "campaign_z_B1",
"campaign_z_B2", "campaign_z_C3", "campaign_z_C3", "campaign_z_B1",
"campaign_z_B2", "campaign_z_C3", "campaign_z_B1", "campaign_z_C3",
"campaign_z_B1", "campaign_z_A1", "campaign_z_C3", "campaign_z_B1",
"campaign_z_B1", "campaign_z_C3", "campaign_z_B1", "campaign_z_A1",
"campaign_z_C3", "campaign_z_C3", "campaign_z_B1", "campaign_z_B2",
"campaign_z_C3", "campaign_z_B1", "campaign_z_C3", "campaign_z_C3"
), com_elm_id = c(808001L, 811001L, 814001L, 509005L, 729060L,
817002L, 820002L, 792002L, 793003L, 820003L, 824003L, 792002L,
811001L, 787001L, 811001L, 468023L, 792002L, 812001L, 812001L,
808001L, 811001L, 468023L, 468006L, 491014L, 825002L, 828002L,
741001L, 825002L, 512001L, 733001L, 808001L, 811001L, 814001L,
509005L, 729060L, 817002L, 820002L, 792002L, 793003L, 820003L,
824003L, 792002L, 811001L, 787001L, 811001L, 468023L, 792002L,
812001L, 812001L, 808001L, 811001L, 468023L, 468006L, 491014L,
825002L, 828002L, 741001L, 825002L, 512001L, 733001L, 808001L,
811001L, 814001L, 509005L, 729060L, 817002L, 820002L, 792002L,
793003L, 820003L, 824003L, 792002L, 811001L, 787001L, 811001L,
468023L, 792002L, 812001L, 812001L, 808001L, 811001L, 468023L,
468006L, 491014L, 825002L, 828002L, 741001L, 825002L, 512001L,
733001L), recipient_id = c(5432L, 5432L, 5432L, 197L, 197L, 8388L,
8388L, 8426L, 8426L, 10903L, 10903L, 14469L, 14469L, 17466L,
17466L, 17807L, 21666L, 23935L, 24287L, 25412L, 25412L, 31361L,
31361L, 31361L, 31365L, 31365L, 40849L, 40860L, 41737L, 41737L,
5432L, 5432L, 5432L, 197L, 197L, 8388L, 8388L, 8426L, 8426L,
10903L, 10903L, 1446945L, 1446945L, 1746645L, 1746645L, 1780745L,
2166645L, 2393545L, 24287L, 25412L, 25412L, 3136145L, 3136145L,
3136145L, 3136545L, 3136545L, 40849L, 40860L, 4173745L, 4173745L,
5432L, 5432L, 5432L, 19732L, 19732L, 838832L, 838832L, 842632L,
842632L, 10903L, 10903L, 14469L, 14469L, 1746632L, 1746632L,
1780732L, 2166645L, 2393545L, 2428745L, 25412L, 25412L, 3136145L,
3136145L, 3136145L, 3136545L, 3136545L, 40849L, 40860L, 41737L,
41737L), step = c(3, 1, 2, 3, 3, 1, 2, 3, 3, 1, 2, 3, 1, 3, 1,
1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 2, 3, 1, 3, 3, 3, 1, 2, 3, 3, 1,
2, 3, 3, 1, 2, 3, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 3, 1, 2, 3,
1, 3, 3, 3, 1, 2, 3, 3, 1, 2, 3, 3, 1, 2, 3, 1, 3, 1, 1, 3, 1,
1, 3, 1, 1, 3, 3, 1, 2, 3, 1, 3, 3), date = structure(c(19029,
19032, 19035, 18778, 18960, 19037, 19040, 19016, 19019, 19040,
19043, 19015, 19032, 19011, 19032, 18746, 19015, 19033, 19033,
19029, 19032, 18746, 18746, 18764, 19044, 19047, 18969, 19044,
18781, 18962, 19029, 19032, 19035, 18778, 18960, 19037, 19040,
19016, 19019, 19040, 19043, 19015, 19032, 19011, 19032, 18746,
19015, 19033, 19033, 19029, 19032, 18746, 18746, 18764, 19044,
19047, 18969, 19044, 18781, 18962, 19029, 19032, 19035, 18778,
18960, 19037, 19040, 19016, 19019, 19040, 19043, 19015, 19032,
19011, 19032, 18746, 19015, 19033, 19033, 19029, 19032, 18746,
18746, 18764, 19044, 19047, 18969, 19044, 18781, 18962), class = "Date")), class = c("tbl_df",
"tbl", "data.frame"), row.names = c(NA, -90L))
Here is the solution that finally worked for me:
df <- data.frame(twin_campaigns=character(),
max_rank=integer(),
count=integer()
)
x <- c("campaign_x","campaign_y","campaign_z")
segments_list <- list()
datv
for (xval in x){
y <- x[! x %in% c(xval)]
for (yval in y){
segment_name <- paste(str_sort(c(xval,yval)),collapse="::")
print(segment_name)
if (!segment_name %in% segments_list) {
segments_list <- c(segments_list,segment_name)
datk <- datv %>%
filter(str_detect(campaign, paste(str_sort(c(xval,yval)),collapse="|"))) %>%
group_by(recipient_id) %>%
summarise(rank = dense_rank(campaign), .groups = 'drop') %>%
group_by(recipient_id,rank) %>%
summarise(count = n(), .groups = 'drop') %>% #used to remove duplicates with count() to sense check work. Can use distinct()
group_by(recipient_id) %>%
summarise(max_rank=max(rank), .groups = 'drop') %>%
group_by(max_rank) %>%
summarise(count=n(), .groups = 'drop')
datj <- add_column(datk, campaigns_segment=stri_join(xval, yval, sep="::"), .before = "max_rank")
print(nrow(datj))
data <- data.frame(datj)
df <- rbind(df, datj)
}
}
}
df
df %>%
pivot_wider(
names_from = max_rank,
values_from = c(count),
names_sep = "_",
names_prefix = "x.",
values_fill =list(Abundance = NA)
) %>%
rename(separate_recipients = x.1, overlapped_recipients=x.2)
Which gives me this correct output:
During my journey of figuring that out I experimented with venn tables, but was not able to get to the answer I want. I am posting another question regarding venn in another post.
My Question is:
1- Consider it a challenge! is anyone able to come up with a better, neater and faster solution than the for loop I developed above. It felt like a waste of resource looping across the entire dataframe for every single combination of campaigns. This would take long time if the dataset is large!
An ideal solution, would be one that identifies all possible combinations of campaigns at the start, then loops once through the dataset incrementing the different segment buckets as it goes along!
