R语言中基于字符串部分匹配的内连接结果为空问题排查
数据框列信息
colnames(uci_ce_inv): [1] "Ndg" "CTP" "CNT_ID" "NOMINAL_EUR" "FXD_CCYPAIR" "ISIN" "SICOVAM" "TRN_ID" "SOURCE" "INCLUDED" [11] "EXCLUDED"
colnames(assess_data): [1] "GROUP_SOURCE" "GROUP" "MD_ISS_NAME" "MD_ISS_RATING" "MD_GROUP" "MD_SECTOR" "MD_CCY" "MD_COUNTRY" [9] "MD_REGION" "MD_SEC_TYPE"
需求与预处理
需要基于uci_ce_inv$TRN_ID与assess_data$GROUP的字符串部分匹配执行内连接,已将对应列转为字符型:
uci_ce_inv$TRN_ID <- as.character(uci_ce_inv$TRN_ID) assess_data$GROUP <- as.character(assess_data$GROUP)
示例数据:
uci_ce_inv$TRN_ID = "123456789"assess_data$GROUP = "ewitwr/kdk/123456789/gfhdhfd"
预期结果:匹配行的assess_data所有列添加到对应uci_ce_inv行中,但尝试以下四种方法后生成的数据框始终为空。
尝试的方法及问题分析
方法1:fuzzy_inner_join + stri_detect_fixed
uci_ce_inv <- uci_ce_inv %>% fuzzy_inner_join(assess_data, by = c("TRN_ID"="GROUP"), match_fun=stri_detect_fixed)
问题:stri_detect_fixed的参数顺序错误。该函数默认逻辑是stri_detect_fixed(字符串, 匹配模式),当前代码把TRN_ID当作字符串、GROUP当作匹配模式,和实际需求(检查GROUP中是否包含TRN_ID)完全相反。
方法2:fuzzy_inner_join + str_detect
uci_ce_inv <- uci_ce_inv %>% fuzzy_inner_join(assess_data, by = c("TRN_ID"="GROUP"), match_fun=str_detect)
问题:与方法1一致,str_detect的参数顺序是str_detect(字符串, 匹配模式),当前代码的匹配方向搞反了,无法检测到GROUP包含TRN_ID的情况。
方法3:regex_inner_join
uci_ce_inv <- uci_ce_inv %>% regex_inner_join(assess_data, by = c("TRN_ID"="GROUP"))
问题:regex_inner_join默认用by左侧列作为正则表达式匹配右侧列,当前逻辑是用TRN_ID去匹配GROUP的完整内容,而非检测GROUP中是否包含TRN_ID,不符合需求。
方法4:自定义partial_join函数
partial_join <- function(x, y, by_x, pattern_y) { idx_x <- sapply(y[[pattern_y]], grep, x[[by_x]]) idx_y <- sapply(seq_along(idx_x), function(i) rep(i, length(idx_x[[i]]))) df <- dplyr::bind_cols(x[unlist(idx_x), , drop = F], y[unlist(idx_y), , drop = F]) return(df) } a <- partial_join(uci_ce_inv,assess_data, by_x="TRN_ID",pattern_y="GROUP")
问题:grep的参数顺序错误,该函数逻辑是grep(匹配模式, 目标字符串),当前代码把GROUP当作匹配模式、TRN_ID当作目标字符串,完全颠倒了需求中的匹配方向,导致找不到匹配项。
正确解决办法
修正方法1/2:调整匹配函数参数顺序
用匿名函数调换参数,确保检测GROUP中是否包含TRN_ID:
# 基于str_detect的正确写法 uci_ce_inv <- uci_ce_inv %>% fuzzy_inner_join(assess_data, by = c("TRN_ID" = "GROUP"), match_fun = function(x, y) str_detect(y, x))
修正方法3:调整正则匹配逻辑
指定匹配方向为GROUP包含TRN_ID:
uci_ce_inv <- uci_ce_inv %>% regex_inner_join(assess_data, by = c("GROUP" = "TRN_ID"), match_fun = function(x, y) str_detect(x, y))
修正方法4:自定义函数调整grep参数顺序
partial_join <- function(x, y, by_x, pattern_y) { # 用TRN_ID作为匹配模式,匹配GROUP中的内容 idx_y <- sapply(x[[by_x]], grep, y[[pattern_y]]) idx_x <- sapply(seq_along(idx_y), function(i) rep(i, length(idx_y[[i]]))) df <- dplyr::bind_cols(x[unlist(idx_x), , drop = F], y[unlist(idx_y), , drop = F]) return(df) } a <- partial_join(uci_ce_inv, assess_data, by_x="TRN_ID", pattern_y="GROUP")
内容的提问来源于stack exchange,提问作者daftpunk81

