2012-03-02 21 views
26

En R, grep generalmente coincide con un vector de varias cadenas contra una expresión regular.R grep: Empareje una cadena contra varios patrones

P: ¿Existe la posibilidad de unir una sola cadena con varias expresiones regulares? (sin bucles a través de cada patrón de expresiones regulares)?

Algunos antecedentes:

tengo 7000 + palabras clave como indicadores para varias categorías. No puedo cambiar ese diccionario de palabras clave. El diccionario estructura tiene las siguientes palabras clave (en la col 1, los números indican las categorías en las que estos pertenecen a palabras clave):

ab 10 37 41 
abbrach* 38 
abbreche 39 
abbrich* 39 
abend* 37 
abendessen* 60 63 
aber 20 23 45 
abermals 37 

tantas palabras clave con Concatenación "|" no es una forma factible (y no sabría cuál de las palabras clave generó el hit). Además, simplemente invertir "patrones" y "cadenas" no funciona, ya que los patrones tienen truncamientos, lo que no funcionaría al revés.

[related question, otro lenguaje de programación]

+2

I como las sugerencias de Dan, pero con un gran conjunto de datos, es posible que se encuentre con problemas de velocidad importantes. Si desea buscar algo en un diccionario y devolver un valor correspondiente, sugeriría un enfoque diferente: dividir las oraciones en vectores de palabras individuales con strsplit y luego aplicar una tabla hash para una búsqueda rápida. Estoy pensando que también puede dividir la palabra clave y los indicadores de categoría en dos columnas separadas en el diccionario. Proporcionaría asistencia allí, pero solo después de que tenga más claro que quiere como resultado final. –

+0

Acordé la reestructuración de los datos del diccionario y el uso de una tabla hash para la búsqueda (según el resultado deseado), pero la coincidencia debería ser relativamente rápida dependiendo del número de cadenas, incluso con una gran cantidad de palabras clave. Agregaré un punto de referencia rápido a mi respuesta. – danpelota

+1

Si realmente tiene muchas palabras (típicamente, todas las palabras en un lenguaje humano, todas las palabras indexadas por google, etc.), puede usar un [árbol de prefijos] (http: // en. wikipedia.org/wiki/Trie) (a veces también se llama "trie"). Pero no conozco ninguna implementación en R. –

Respuesta

28

¿Qué pasa con la aplicación de la función RegExpr sobre un vector de palabras clave?

keywords <- c("dog", "cat", "bird") 

strings <- c("Do you have a dog?", "My cat ate by bird.", "Let's get icecream!") 

sapply(keywords, regexpr, strings, ignore.case=TRUE) 

    dog cat bird 
[1,] 15 -1 -1 
[2,] -1 4 15 
[3,] -1 -1 -1 

    sapply(keywords, regexpr, strings[1], ignore.case=TRUE) 

dog cat bird 
    15 -1 -1 

Los valores devueltos son la posición del primer carácter en el partido, con -1 significado ninguna coincidencia.

Si la posición del partido es irrelevante, utilizar grepl lugar:

sapply(keywords, grepl, strings, ignore.case=TRUE) 

     dog cat bird 
[1,] TRUE FALSE FALSE 
[2,] FALSE TRUE TRUE 
[3,] FALSE FALSE FALSE 

Actualización: Esto funciona relativamente rápido en mi sistema, incluso con un gran número de palabras clave:

# Available on most *nix systems 
words <- scan("/usr/share/dict/words", what="") 
length(words) 
[1] 234936 

system.time(matches <- sapply(words, grepl, strings, ignore.case=TRUE)) 

    user system elapsed 
    7.495 0.155 7.596 

dim(matches) 
[1]  3 234936 
+0

¡Gracias por su respuesta y sus comentarios! Finalmente, hice un enfoque combinado: un trie redujo el conjunto de posibles coincidencias a ~ 5% del tamaño original, y la función sapply hizo el grep. –

+0

Y luego para ver cuántas de las palabras clave coinciden por oración/cadena, en el marco de datos final, número: num.matches <- apply (data.frame (coincidencias), 1, función (z) sum (z == TRUE)) . Y para buscar qué secuencia original tiene, digamos, 2 coincidencias, número: cadenas [num.matches == 2] # Salida: [1] "Mi gato comió de pájaro". –

+0

¿Qué sucede si quiere reemplazar un producto, en el que no solo lee palabras clave para buscar, sino también sus reemplazos? – user1603472

2

Para expandir el other answer, para transformar la salida sapply() en un vector lógico útil, necesita usar un paso apply().

keywords <- c("dog", "cat", "bird") 
strings <- c("Do you have a dog?", "My cat ate by bird.", "Let's get icecream!") 
(matches <- sapply(keywords, grepl, strings, ignore.case=TRUE)) 
#  dog cat bird 
# [1,] TRUE FALSE FALSE 
# [2,] FALSE TRUE TRUE 
# [3,] FALSE FALSE FALSE 

para saber qué cadenas contienen cualquier de las palabras clave (patrones):

apply(matches, 1, any) 
# [1] TRUE TRUE FALSE 

saber qué palabras clave (patrones) fueron emparejados en las cadenas proporcionadas:

apply(matches, 2, any) 
# dog cat bird 
# TRUE TRUE TRUE 
Cuestiones relacionadas