Identificación de patrones en dos cadenas en R
Quiero evaluar si ColA contiene una nueva cadena que ColB. Sin embargo, no estoy interesado en ciertos tipos de cadena, por ejemplo, aceite. Me gustaría tener una variable indicadora como sigue:
ColA ColB Ind
-------------------------- ------------------------ -----
coconut+grape+pine grape+coconut TRUE
orange+apple+grape+pine grape+coconut TRUE
grape+pine grape+oil TRUE
oil+grape grape+apple FALSE
grape grape+oil FALSE
grape+pine grape+orange+pine FALSE
¿Alguna sugerencia usando R?
¡Muchas gracias!
Pregunta hecha hace 3 años, 4 meses, 28 días - Por codecraftsman32c9
4 Respuestas:
-
Ya que tenemos que dividir las cuerdas, empezaremos con
strsplit
,strsplit(dat$ColA, '+', fixed = TRUE) # [[1]] # [1] "coconut" "grape" "pine" # [[2]] # [1] "orange" "apple" "grape" "pine" # [[3]] # [1] "grape" "pine" # [[4]] # [1] "oil" "grape" # [[5]] # [1] "grape" # [[6]] # [1] "grape" "pine"
Desde aquí, queremos determinar qué hay en
ColA
que no estáColB
. Voy a usarMap
para corrersetdiff
en cada conjunto (ColA
's[[1]]
conColB
's[[1]]
, etc.Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE)) # [[1]] # [1] "pine" # [[2]] # [1] "orange" "apple" "pine" # [[3]] # [1] "pine" # [[4]] # [1] "oil" # [[5]] # character(0) # [[6]] # character(0)
Para determinar cuál tiene "nuevas palabras", podemos comprobar por la longitud no cero usando
lengths(.) > 0
:lengths(Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE))) > 0 # [1] TRUE TRUE TRUE TRUE FALSE FALSE
Pero ya que no te importa
oil
Tenemos que eliminar eso también.lapply(Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE)), setdiff, "oil") # [[1]] # [1] "pine" # [[2]] # [1] "orange" "apple" "pine" # [[3]] # [1] "pine" # [[4]] # character(0) # [[5]] # character(0) # [[6]] # character(0) lengths(lapply(Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE)), setdiff, "oil")) > 0 # [1] TRUE TRUE TRUE FALSE FALSE FALSE
@akrun sugirió una variante tidiversa:
library(dplyr) library(purrr) # map2_lgl library(stringr) # str_extract_all dat %>% mutate( new = map2_lgl( str_extract_all(ColB, "\\w+"), str_extract_all(ColA, "\\w+"), ~ !all(setdiff(.y, "oil") %in% .x) ) ) # ColA ColB Ind new # 1 coconut+grape+pine grape+coconut TRUE TRUE # 2 orange+apple+grape+pine grape+coconut TRUE TRUE # 3 grape+pine grape+oil TRUE TRUE # 4 oil+grape grape+apple FALSE FALSE # 5 grape grape+oil FALSE FALSE # 6 grape+pine grape+orange+pine FALSE FALSE
Datos
dat <- structure(list(ColA = c("coconut+grape+pine", "orange+apple+grape+pine", "grape+pine", "oil+grape", "grape", "grape+pine"), ColB = c("grape+coconut", "grape+coconut", "grape+oil", "grape+apple", "grape+oil", "grape+orange+pine"), Ind = c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE)), class = "data.frame", row.names = c(NA, -6L))
Respondida el Dec 18, 2020 a las 16:57 - por coderchampion
Votos positivos: 0 | Votos negativos: 0 -
Aquí hay una solución similar a r2evans's que llama
strsplit
sólo una vez con la ayuda dedo.call
.rid <- function(x) x[!x %in% z] ## helper FUN to get rid of the oil z <- "oil" L <- sapply(unname(dat), strsplit, "\\+") dat$ind <- sapply(1:nrow(L), function(x) length(do.call(setdiff, rev(Map(rid, L[x,]))))) > 0 dat # V1 V2 ind # 1 grape+coconut coconut+grape+pine TRUE # 2 grape+coconut orange+apple+grape+pine TRUE # 3 grape+oil grape+pine TRUE # 4 grape+apple oil+grape FALSE # 5 grape+oil grape FALSE # 6 grape+orange+pine grape+pine FALSE
Datos:
dat <- structure(list(V1 = c("grape+coconut", "grape+coconut", "grape+oil", "grape+apple", "grape+oil", "grape+orange+pine"), V2 = c("coconut+grape+pine", "orange+apple+grape+pine", "grape+pine", "oil+grape", "grape", "grape+pine")), row.names = c(NA, -6L), class = "data.frame")
Respondida el Dec 18, 2020 a las 17:04 - por bytebard66b1
Votos positivos: 0 | Votos negativos: 0 -
Para lograr esto en R, puedes utilizar la función
grepl()
para buscar patrones en las cadenas de texto. Para este caso en particular, puedes usar expresiones regulares para buscar si la cadena de ColA contiene una nueva cadena presente en ColB, pero excluyendo ciertos patrones como "aceite".Aquí te dejo un código para lograr lo que necesitas:
R
Crear un dataframe con los datos proporcionados
df <- data.frame(ColA = c("coconut+grape+pine", "orange+apple+grape+pine", "grape+pine", "oil+grape", "grape", "grape+pine"), ColB = c("grape+coconut", "grape+coconut", "grape+oil", "grape+apple", "grape+oil", "grape+orange+pine"))Función para evaluar si la cadena de ColA contiene una nueva cadena que ColB, excluyendo "aceite"
evaluar_cadenas <- function(cadena_A, cadena_B) { patron_excluir <- "aceite" ifelse(grepl(patron_excluir, cadena_A), FALSE, ifelse(grepl(patron_excluir, cadena_B), FALSE, any(!grepl(paste0(cadena_B, collapse = "|"), cadena_A)))) }Aplicar la función a cada fila del dataframe
df$Ind <- mapply(evaluar_cadenas, df$ColA, df$ColB)Mostrar el resultado
print(df)Este código creará una nueva columna "Ind" en el dataframe que contendrá un valor TRUE si ColA contiene una nueva cadena que ColB (excluyendo "aceite") y FALSE en caso contrario.
Espero que esta solución sea de ayuda. ¡Déjame saber si tienes alguna otra pregunta o si necesitas más ayuda!
Respondida el Dec 19, 2020 a las 16:56 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
library(stringr)
Crear una función personalizada para identificar patrones
match_pattern <- function(str1, str2, exclude_pattern) {Excluir patrones no deseados
exclude_pattern <- paste0(".", exclude_pattern, ".")Verificar si el patrón está presente en str1, excluyendo los patrones no deseados
str_detect(str1, str_replace_all(str2, exclude_pattern, "")) }Crear una variable indicadora
Ind <- sapply(ColA, match_pattern, ColB, "oil")Respondida el Dec 19, 2020 a las 17:05 - por Gemini
Votos positivos: 0 | Votos negativos: 0