2016-07-30 5 views
0

komplett bearbeitet, großer Dank Shayaa für den Rat!Mindestabstand Funktion zwischen Strings

Aus Sätzen in einer Matrix (eingelesen von csv) sollen Wörter erkannt werden, die in Listen gespeichert sind (eingelesen aus txt).

sentences_list <- matrix(c(
    "this screen is great", 
    "this camera is not bad", 
    "everything good but the camera is awesome", 
    "everything bad but the camera is awesome", 
    "battery is ok but the camera is awesome"), ncol = 1) 

word_list_one <-list("screen", "camera", "battery") 
word_list_two <-list("good", "great", "awesome") 
word_list_three <-list("bad", "awful", "poor") 
word_list_four <-list("not", "don't", "neither") 

    one <- apply(sentences_list, 2, function(x) { 
     str_detect(x, paste(word_list_one, sep = '|', collapse = '|')) 
    }) 

    two <- apply(sentences_list, 2, function(x) { 
     str_detect(x, paste(word_list_two, sep = '|', collapse = '|')) 
    }) 

    three <- apply(sentences_list, 2, function(x) { 
     str_detect(x, paste(word_list_three, sep = '|', collapse = '|')) 
    }) 

    four <- apply(sentences_list, 2, function(x) { 
     str_detect(x, paste(word_list_four, sep = '|', collapse = '|')) 
    }) 

Der folgende Code kann verwendet werden, um zu überprüfen, welche Wörter gefunden wurden. (Die Ergebnisse werden nicht direkt angezeigt gespeichert, da die Anzahl der Ergebnisse auf eine bestimmte Weise in der Zeit nach gezählt wird)

row=5 

print(sentences_list[row]) 
c(str_extract(sentences_list[row], paste(word_list_one, sep = '|', collapse = '|'))) 
c(str_extract(sentences_list[row], paste(word_list_two, sep = '|', collapse = '|'))) 
c(str_extract(sentences_list[row], paste(word_list_three, sep = '|', collapse = '|'))) 
c(str_extract(sentences_list[row], paste(word_list_four, sep = '|', collapse = '|'))) 

Für row=1 und row=2 alles funktioniert, wie es sollte, aber nicht für die folgenden. Dies liegt daran, dass nur die erste Übereinstimmung in einem Satz von word_list_x zurückgegeben wird. Was ich lieber möchte, dass der Code zu tun ist, gibt das Wort für eine word_list_x zurück, die dem Wort in einem anderen word_list_ am nächsten ist.

so für row=3 in sentences_list das Ergebnis für die word_list_two = "good", weil es zuerst gefunden wird. Was sollte das Ergebnis sein, ist word_list_two = "awesome", weil in dem Satz von row=3 es näher an das Ergebnis in word_list_one = "camera" gefunden steht.

wie für row=4 in sentences_list das Ergebnis für die word_list_three = "bad" und word_list_two = "awesome". Da das Ergebnis von word_list_two näher an das in word_list_one = "camera" gefundene Ergebnis ist, sollte nur das Ergebnis von word_list_two = "awesome" zurückgegeben werden, wobei word_list_three = " " leer gelassen wird.

wie für row=5 in sentences_list das Ergebnis für die word_list_one = "battery", weil es zuerst gefunden wird. Was das Ergebnis sein sollte, ist word_list_one = "camera", weil es in dem Satz von row=5 näher an das Ergebnis in word_list_two= "great" gefunden wird.

Offensichtlich bin ich als Anfänger völlig überfordert mit dem Umfang dieses Projekts und ich bin sehr dankbar für jede Hilfe, die Sie zur Verfügung stellen können, vielen Dank!

+0

Nur fyi, das ist kein reproduzierbares Beispiel. Ich kann den Code nicht starten und die Ergebnisse reproduzieren. Ich habe kein 'df' mit Wortlisten. Im Großen und Ganzen ist ein 'dat.frame' nicht das beste Repository für Ihre Wörter. Ein Vektor ist. Für viele Vektoren von Wörtern möchten Sie eine Liste verwenden. Vielleicht können Sie diese Frage noch einmal bearbeiten. – shayaa

+0

Vielen Dank für Ihre Beratung, ich weiß es zu schätzen! Ich bin immer noch sehr neu in R und auch Stackoverflow. Ich werde versuchen, die Frage in Bezug auf das reproduzierbare Beispiel in einem Moment zu verbessern. Ich kenne mich nicht mit allen Repositories aus, aber ich habe Listen mit den Wörtern erstellt, die ich im Text finden möchte. Was den Text angeht, kann ich meine CSV-Datei nicht mit mehreren Sätzen für jedes Element in etwas anderes als einem Datenrahmen oder einer Matrix einlesen. Würde eine Matrix tun? – dennis

+0

Hi @dennis, ich habe eine kurze Frage, was ist, wenn das letzte Element von 'sets_list' zum Beispiel" Akku ist gut, aber die Kamera ist großartig "ist, was wäre das Ergebnis? In diesem Fall könnten Sie Entfernungen von zwei verschiedenen Wörtern von "word_list_one" erkennen: "camera" und "battery", und beide hätten ein Wort von "word_list_two" in gleicher Entfernung: "good" und "awesome". –

Antwort

0

Ok, hier ist, was ich gefunden habe. Ich habe einen Ansatz gewählt, bei dem das Ergebnis ein data.frame ist, wobei die erste Spalte ein Wort aus der ersten Liste enthält und die anderen Spalten "zwei", "drei" und "vier" das nächste Wort jeder dieser Listen enthält Wort in der ersten Spalte. Zuerst werden zwei Funktionen Mindestabstände berechnen:

getMinimumDistanceWord <- function(text, word, wordList){ 
    min <- " " 
    minDist <- 1000 
    for (w in wordList){ 
    d <- distanceBetweenWords(text, word, w) 
    if (d != 0 && d < minDist){ 
     min <- w 
     minDist <- d 
    } 
    } 
    return (list(min, minDist)) 
} 


distanceBetweenWords <- function(text, word1, word2){ 
    x <- strsplit(text, " ")[[1]] 
    dist <- abs(grep(word1, x) - grep(word2, x)) 
    if (length(dist) == 0) return (0) 
    else return (dist) 
} 

nun über den Satz Liste iterieren und die Mindestabstände berechnen:

res <- data.frame(one = character(), two = character(), three = character(), four = character(), stringsAsFactors=FALSE) 
i <- 1 
for(elem in sentences_list){ 
    base.word.list <- unlist(str_extract_all(elem, paste(word_list_one, sep = '|', collapse = '|'))) 
    res[i, 1] <- base.word.list[1] 
    res[i, 2] <- getMinimumDistanceWord(elem, base.word.list[1], word_list_two)[1] 
    res[i, 3] <- getMinimumDistanceWord(elem, base.word.list[1], word_list_three)[1] 
    res[i, 4] <- getMinimumDistanceWord(elem, base.word.list[1], word_list_four)[1] 
    if (length(base.word.list) != 1){ 
    currentDistance2 <- as.numeric(unlist(getMinimumDistanceWord(elem, base.word.list[1], word_list_two))[2]) 
    currentDistance3 <- as.numeric(unlist(getMinimumDistanceWord(elem, base.word.list[1], word_list_three))[2]) 
    currentDistance4 <- as.numeric(unlist(getMinimumDistanceWord(elem, base.word.list[1], word_list_four))[2]) 
    for(currentWord in base.word.list){ 
     if (getMinimumDistanceWord(elem, currentWord, word_list_two)[2] < as.numeric(currentDistance2)){ 
     currentDistance2 <- getMinimumDistanceWord(elem, currentWord, word_list_two)[2] 
     res[i, 1] <- currentWord 
     res[i, 2] <- getMinimumDistanceWord(elem, currentWord, word_list_two)[1] 
     } 
     if (getMinimumDistanceWord(elem, currentWord, word_list_three)[2] < as.numeric(currentDistance3)){ 
     currentDistance3 <- getMinimumDistanceWord(elem, currentWord, word_list_three)[2] 
     res[i, 1] <- currentWord 
     res[i, 3] <- getMinimumDistanceWord(elem, currentWord, word_list_three)[1] 
     } 
     if (getMinimumDistanceWord(elem, currentWord, word_list_four)[2] < as.numeric(currentDistance4)){ 
     currentDistance4 <- getMinimumDistanceWord(elem, currentWord, word_list_four)[2] 
     res[i, 1] <- currentWord 
     res[i, 4] <- getMinimumDistanceWord(elem, currentWord, word_list_four)[1] 
     } 
    } 
    } 
    i <- i+1 
} 

Das Ergebnis data.frame sein würde:

 one  two three four 
1 screen great   
2 camera   bad not 
3 camera awesome   
4 camera awesome bad  
5 camera awesome 

Zum Beispiel sagt die erste Reihe, dass das nächste Wort zum Wort "Bildschirm" (in der Liste eins) "groß" (von der Liste zwei) ist, und dass es keine anderen nächsten Wörter aus Listen "thre e "und" vier ". Ähnlich sagt die fünfte Reihe, dass das nächste Wort (im fünften Satz) zu "Kamera" "fantastisch" ist. Die zweite Zeile sagt, dass in dem zweiten Satz ein "nächstes" Wort zu "Kamera" in der dritten Liste ("schlecht") existiert, und es gibt auch ein anderes nächstes Wort ("nicht") aus der vierten Liste.

Ich hoffe, das hilft.

0

Warum nicht so etwas wie dies

ich Ihre Daten bearbeiten, so dass es

läuft
df <- c("second" , "word1", "word2", "word3", 
      "word4","first", "word1", "word2", "third") 
one <- "third" 
two <- c("second", "third") 

Spiel jeden Vektor

match1 <-match(one, df) 
match2 <- match(two, df) 
match3 <- match("first",df) 

Bestimmen Sie die Position des angepassten Vektors, der das Wort am nächsten ist, Sie suchen in diesem Fall das Wort "first"

closest <- which.min(abs(match2 - match3)) 

Jetzt Ihre Antworten

df[match1] 
[1] "third" 

df[match2[closest]] 
[1] "third" 

Edited Ihre Änderungen zu beantworten:

ich tun würde, als

library(stringr) 
sentences_list <- list("this screen is great", 
    "this camera is not bad", 
    "everything good but the camera is awesome", 
    "everything bad but the camera is awesome", 
    "battery is ok but the camera is awesome") 

word_list_one <- c("screen", "camera", "battery") 
word_list_two <- c("good", "great", "awesome") 
word_list_three <- c("bad", "awful", "poor") 
word_list_four <- c("not", "don't", "neither") 

l <- lapply(sentences_list, str_match_all, word_list_one) 

Die Funktion str_match_all folgt mit je drei Elemente eine Liste von 5 Listen zurückkehren .Die erste Liste in l gibt die Übereinstimmungen aus der ersten Wortliste sowie das übereinstimmende Wort zurück.

Dies ist das gleiche wie Speicher ihnen, wie Sie in Ihrer ursprünglichen Matrix taten und mit

apply(sentences_list,1, str_match_all, word_list_one) 

Sie sollten in der Lage sein, die beispielsweise mit der ursprünglichen Antwort zu vervollständigt ich zur Verfügung gestellt.

+0

Vielen Dank für Ihre Antwort! Ich bekomme es für den Teil, den du gerade bearbeitet hast. Für die folgende Implementierung der ursprünglichen Antwort, die Sie zur Verfügung gestellt haben, funktioniert der Code nicht wirklich. Ich bekomme jetzt die "match1" usw. als "NA NA NA NA NA". Für beide Optionen, die Sie zur Verfügung gestellt haben, also das "apply" und das "lapply". Außerdem verstehe ich nicht wirklich, was Sie mit match und am nächsten gemacht haben. – dennis

Verwandte Themen