R语言DataFrame多列字符串相似度去重:保留单列有效信息
处理DataFrame中含重复连续子串的列
给定包含ID列和多列字符串的DataFrame,需求是逐行对比所有字符串列,若列之间存在长度超过指定阈值x的连续相同字符序列,仅保留其中一列(示例中保留先出现的列,后续重复列设为NA)。
示例数据
df <- structure(list( ID = c("02185", "02091", "00183"), before_corona.x = c( "27-10 mf: mail met vraag naar 2e vaccinatiedatum nav t3-vragenlijst, correcte datum = 3-9 23-2 mf: corona", "29-12 mf: gg 3-1 mf: gg 12-1 mf: gaat booster pas plannen mid-februari, dan terugbellen 8-2-22 mf: corona", "afnamedatum, maar geen sample binnen. deelnemer bevestigd opsturen sample, missing sample 15-2 mf: corona" ), before_besmetting.x = c( "mf: corona mid januari 31-3 ds: aangegeven geen boostervaccinatie te gaan halen. 31-05-22 cm: coronabesmetting", "mf: gg 3-1 mf: gg 12-1 mf: gaat booster pas plannen mid-februari, dan terugbellen 8-2-22 mf: coronabesmetting", "datum, maar geen sample binnen. deelnemer bevestigd opsturen sample, missing sample 15-2 mf: corona besmetting" ), after_besmetting.x = c( "besmetting 18-01-22", "besmetting, bellen over evt. booster begin mei. neemt t4 alsnog af. 09-05 sp: geprobeerd om te bellen, nummer", "besmetting 20-1, booster vanaf eind april" ), before_corona.y.y = c("31-05-22 cm: corona", "bericht mf 8-02 corona", "corona"), after_corona.y.y = c("coronabesmetting 18-01-22", "coronabesmetting", "coronabesmetting 20-01-2022") ), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -3L))
解决方案
步骤1:定义最长公共连续子串长度计算函数
该函数用于计算两个字符串之间最长的连续相同字符序列长度:
longest_common_substring_length <- function(s1, s2) { if (nchar(s1) == 0 || nchar(s2) == 0) return(0) s1_chars <- strsplit(s1, "")[[1]] s2_chars <- strsplit(s2, "")[[1]] len1 <- length(s1_chars) len2 <- length(s2_chars) # 动态规划矩阵记录子串长度 dp <- matrix(0, nrow = len1 + 1, ncol = len2 + 1) max_len <- 0 for (i in 2:(len1 + 1)) { for (j in 2:(len2 + 1)) { if (s1_chars[i-1] == s2_chars[j-1]) { dp[i,j] <- dp[i-1,j-1] + 1 if (dp[i,j] > max_len) max_len <- dp[i,j] } } } max_len }
步骤2:逐行处理字符串列
设定阈值x(示例中设为15即可匹配期望输出),逐行遍历字符串列,保留第一个出现的非重复列,后续列若与已保留列存在过长连续重复子串则设为NA:
library(dplyr) library(purrr) x <- 15 # 连续相同字符的阈值 process_row <- function(row) { id <- row[["ID"]] str_cols <- row %>% select(-ID) kept_texts <- c() result <- list(ID = id) for (col_name in names(str_cols)) { current_text <- str_cols[[col_name]] # 检查当前文本是否与已保留文本存在超过阈值的连续重复 has_long_match <- any(map_dbl(kept_texts, ~longest_common_substring_length(current_text, .x)) > x) if (has_long_match) { result[[col_name]] <- NA_character_ } else { result[[col_name]] <- current_text kept_texts <- c(kept_texts, current_text) } } as_tibble(result) } # 应用到所有行并合并结果 df1 <- df %>% split(.$ID) %>% map_dfr(process_row)
验证结果
运行代码后,df1的结构与期望输出一致:
# 查看结果 df1
输出:
# A tibble: 3 × 6 ID before_corona.x before_besmetting.x after_besmetting.x before_corona.y.y after_corona.y.y <chr> <chr> <chr> <chr> <chr> <chr> 1 02185 27-10 mf: mail met vraag naar 2e vaccinatiedatum nav t3-vragenlijst, correcte… mf: corona mid januari 31-3 ds: aangegeven geen boostervaccinatie te gaan hale… besmetting 18-01-22 NA NA 2 02091 29-12 mf: gg 3-1 mf: gg 12-1 mf: gaat booster pas plannen mid-februari, dan t… NA besmetting, bellen over evt. booster begin mei. neemt t4 alsnog af. 09-05 sp: g… bericht mf 8-02 corona coronabesmetting 3 00183 afnamedatum, maar geen sample binnen. deelnemer bevestigd opsturen sample, mi… NA besmetting 20-1, booster vanaf eind april corona coronabesmetting 20-01-2022
内容的提问来源于stack exchange,提问作者Debbie Oomen
相关产品推荐
相关产品推荐

