如何基于商品集合包含关系合并两个R语言数据框?
数据准备
交易记录数据框df1
set.seed(99) df1 <- tibble::tibble( ID = 1:10, Items = replicate(10, paste0('item-', sample(1:10, sample(3:5)[1]), collapse = ', ')) )
df1的输出:
A tibble: 10 × 2ID Items
1 1 item-6, item-5, item-3
2 2 item-6, item-4, item-9, item-7
3 3 item-6, item-4, item-5
4 4 item-1, item-7, item-2, item-9
5 5 item-5, item-8, item-7, item-2
6 6 item-10, item-1, item-6, item-4
7 7 item-6, item-7, item-9, item-4, item-5
8 8 item-6, item-9, item-1, item-3, item-5
9 9 item-6, item-8, item-7, item-3, item-9
10 10 item-4, item-7, item-5, item-9
优惠券条件查找表df2
df2 <- tibble::tibble( Items = c("item-4, item-6", "item-7, item-9"), Coupons = c("coupon-1", "coupon-2") )
df2的输出:
A tibble: 2 × 2Items Coupons
1 item-4, item-6 coupon-1
2 item-7, item-9 coupon-2
需求说明
- 规则:同时购买
item-4和item-6可获得coupon-1;同时购买item-7和item-9可获得coupon-2 - 预期输出:每笔交易匹配所有满足的优惠券,满足多个条件的交易重复显示对应优惠券,不满足则显示
NA
解决方案
常规的merge()或dplyr::left_join()无法直接实现需求,因为需要检查交易商品集合是否包含优惠券的所有必要商品,而非直接匹配字符串。可按以下步骤处理:
步骤1:预处理优惠券条件
拆分优惠券的商品条件为列表形式,方便后续集合检查:
library(dplyr) library(tidyr) df2_processed <- df2 %>% separate_rows(Items, sep = ", ") %>% group_by(Coupons) %>% summarise(required_items = list(Items))
步骤2:匹配交易与优惠券
逐行检查每笔交易是否满足优惠券条件,展开匹配结果:
result <- df1 %>% rowwise() %>% mutate( # 拆分当前交易的商品为列表 transaction_items = list(str_split(Items, ", ")[[1]]), # 筛选所有满足条件的优惠券 matched_coupons = list( df2_processed$Coupons[ sapply(df2_processed$required_items, function(x) all(x %in% transaction_items)) ] ) ) %>% ungroup() %>% # 展开匹配结果,无匹配则保留NA unnest(matched_coupons, keep_empty = TRUE) %>% rename(Coupons = matched_coupons) %>% select(-transaction_items)
验证结果
运行后得到的结果与预期一致:
A tibble: 12 × 3ID Items Coupons
1 1 item-6, item-5, item-3 NA
2 2 item-6, item-4, item-9, item-7 coupon-1
3 2 item-6, item-4, item-9, item-7 coupon-2
4 3 item-6, item-4, item-5 coupon-1
5 4 item-1, item-7, item-2, item-9 coupon-2
6 5 item-5, item-8, item-7, item-2 NA
7 6 item-10, item-1, item-6, item-4 coupon-1
8 7 item-6, item-7, item-9, item-4, item-5 coupon-1
9 7 item-6, item-7, item-9, item-4, item-5 coupon-2
10 8 item-6, item-9, item-1, item-3, item-5 NA
11 9 item-6, item-8, item-7, item-3, item-9 coupon-2
12 10 item-4, item-7, item-5, item-9 coupon-2
思路说明
- 常规连接方法基于字符串匹配,无法处理集合包含的逻辑,因此需要先拆分商品条件
- 用
rowwise()逐行处理交易,通过集合包含检查筛选符合条件的优惠券 - 最后用
unnest()展开匹配结果,实现多条件交易的重复显示
内容的提问来源于stack exchange,提问作者user18894435

