R语言 如果多列包含x数量的相似字符且顺序相似,则保留一列

amrnrhlw  于 2023-03-27  发布在  其他
关注(0)|答案(1)|浏览(108)

我有一个dataframe,它有一个ID列和多个包含字符串的列。下面你可以找到一个dataframe的小样本。我需要做的是比较每行的所有列,如果列有超过x数量的字符以相同的顺序,只保留一个列的此信息(或将其放置在一个新创建的列中,两者都可以)。

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))

这是我需要的输出:

df1 <- 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", 
    NA, NA), 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(NA, 
    "bericht mf 8-02 corona", "corona"), after_corona.y.y = c(NA, 
    "coronabesmetting", "coronabesmetting 20-01-2022")), class = c("tbl_df", 
    "tbl", "data.frame"), row.names = c(NA, -3L))

谢谢!

eanckbw9

eanckbw91#

这里有一个解决方案--它有很多部分,但我想不出更简单的。

library(dplyr)
library(tidyr)
library(stringr)
library(purrr)

replace_duplicates <- function(x, n) {
  # This function takes a vector and a length n and returns NA if an element of
  # the vector has a "duplicate" substring of length n at lower index in the
  # vector.
  substrings_list <- map(x, \(s) get_all_substrings(s, n = n))
  
  if_else(
    c(FALSE, map_lgl(2:length(x), \(i) is_duplicate(substrings_list, i))),
    NA,
    x
  )
}

get_all_substrings <- function(s, n) {
  # This takes a character of length one and returns a vector of all substrings 
  # of length n
  n_substrings <- if (str_length(s) <= n) 1 else str_length(s) - n
  
  map_chr(1:n_substrings, \(i) str_sub(s, start = i, end = i + n))
}

is_duplicate <- function(l, i) {
  # This function takes a list of substring character vectors and an index,
  # returning TRUE if the list is a "duplicate" at that index.
  any(map_lgl(1:(i - 1), \(j) any(l[[i]] %in% l[[j]])))
}

df_new <- df |>
  pivot_longer(cols = !ID) |> 
  mutate(value = replace_duplicates(value, n = 18), .by = ID) |> 
  pivot_wider()

相关问题