2012-03-02 11 views
26

W języku R grep zwykle dopasowuje wektor wielu ciągów do jednego wyrażeń regularnych.R grep: Dopasuj jeden ciąg do wielu wzorców

Pytanie: Czy istnieje możliwość dopasowania pojedynczego ciągu do wielu wyrażeń regularnych? (bez przechodzenia przez każdy pojedynczy wzór regexp)?

Niektóre tła:

mam 7000+ słów kluczowych jako wskaźników dla kilku kategoriach. Nie mogę zmienić tego słownika słów kluczowych. Słownik ma następującą strukturę (słowo w Kol 1, cyfry oznaczają kategorie gdzie te słowa należą do):

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

łącząc tak wiele słów kluczowych z „|” nie jest wykonalnym sposobem (i nie wiedziałbym, które słowo kluczowe wygenerowało trafienie). Również, po prostu odwrócenie "wzorców" i "ciągów znaków" nie działa, ponieważ wzorce mają obcinania, które nie działałyby na odwrót.

[related question, inny język programowania]

+2

I takie jak sugestie Dana, ale z dużym zbiorem danych możesz mieć problemy z szybkością. Jeśli chcesz wyszukać coś w słowniku i zwrócić odpowiednią wartość, sugerowałbym inne podejście: dzielenie zdań na wektory pojedynczych słów za pomocą strsplit, a następnie stosowanie tabeli mieszania dla szybkiego wyszukiwania. Myślę, że możesz również podzielić słowo kluczowe i wskaźniki kategorii na dwie osobne kolumny w słowniku. Pomagałbym tam, ale dopiero po tym, jak będziesz bardziej jasne, że chcesz jako ostateczny wynik. –

+0

Uzgodniono w sprawie restrukturyzacji danych słownikowych i użycia tabeli mieszania do wyszukiwania (w zależności od pożądanego wyniku), ale dopasowanie powinno być stosunkowo szybkie w zależności od liczby łańcuchów, nawet z dużą liczbą słów kluczowych. Dodam szybki benchmark do mojej odpowiedzi. – danpelota

+1

Jeśli naprawdę masz dużo słów (zazwyczaj wszystkie słowa w ludzkim języku, wszystkie słowa indeksowane przez google, itp.), możesz użyć [drzewa prefiksów] (http: // en. wikipedia.org/wiki/Trie) (czasem nazywany też "trie"). Ale nie jestem świadomy żadnej implementacji w R. –

Odpowiedz

28

Co o zastosowaniu funkcji RegExpr nad wektorem słów kluczowych?

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 

Wartości zwracane są pozycja pierwszego znaku w meczu z -1 rozumieniu Brak odpowiednika.

Jeśli pozycja meczu nie ma znaczenia, użyj grepl zamiast:

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

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

Aktualizacja: ten przebiega stosunkowo szybko w moim systemie, nawet z dużej liczby słów kluczowych:

# 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

Dziękuję za odpowiedź i komentarze! W końcu zrobiłem podejście łączone: trie zredukowało zestaw możliwych dopasowań do ~ 5% pierwotnego rozmiaru, a funkcja sapply wykonała grep. –

+0

A następnie, aby zobaczyć, ile słów kluczowych pasuje do zdania/ciągu, w ostatecznej ramce danych, wydanie: num.matches <- apply (data.frame (mecze), 1, funkcja (z) suma (z == TRUE)) . I aby sprawdzić, który oryginalny ciąg ma, powiedzmy, 2 dopasowania, wydać: ciągi [num.matches == 2] # Wynik: [1] "Mój kot jadł przez ptaka." –

+0

Co zrobić, jeśli chcesz dokonać wymiany, w której nie czytasz słów kluczowych do wyszukania, ale także ich zamienników? – user1603472

2

Aby rozwinąć na other answer, aby przekształcić dane wyjściowe sapply() w użyteczny wektor logiczny, należy dodatkowo wykonać krok 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 

Aby wiedzieć, które struny zawierać żadnego ze słów kluczowych (wzory):

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

wiedzieć, jakie słowa kluczowe (wzory) dobrano w dostarczonych strun:

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