2009-03-31 22 views
5

Angenommen, ich habe eine Wortfolge: 'a b c d e f'. Ich möchte eine Liste von Wörtern mit mehreren Wörtern aus dieser Zeichenfolge generieren.Wie erzeuge ich Mehrwortbegriffe rekursiv?

Wortfolge ist wichtig. Der Begriff 'f e d' sollte nicht aus dem obigen Beispiel generiert werden.

Edit: Auch Wörter sollten nicht übersprungen werden. 'a c' oder 'b d f' sollte nicht generiert werden.

Was ich habe jetzt:

doc = 'a b c d e f' 
terms= [] 
one_before = None 
two_before = None 
for word in doc.split(None): 
    terms.append(word) 
    if one_before: 
     terms.append(' '.join([one_before, word])) 
    if two_before: 
     terms.append(' '.join([two_before, one_before, word])) 
    two_before = one_before 
    one_before = word 

for term in terms: 
    print term 

Drucke:

a 
b 
a b 
c 
b c 
a b c 
d 
c d 
b c d 
e 
d e 
c d e 
f 
e f 
d e f 

Wie würde ich dies machen eine rekursive Funktion, so dass ich es eine variable maximale Anzahl von Wörtern passieren kann pro Semester?

Anwendung:

Ich werde dies unter Verwendung von Mehrwortbegriffe aus lesbarem Text in HTML-Dokumenten zu erzeugen. Das Gesamtziel ist eine latente semantische Analyse eines großen Korpus (etwa zwei Millionen Dokumente). Dies ist der Grund, warum es wichtig ist, die Reihenfolge der Wörter zu beachten (Natural Language Processing und so weiter).

+0

Der Einfachheit halber ersetzte ich einzelne Buchstaben für Wörter. – tgray

+0

meinst du "variable maximale Anzahl von Begriffen pro Wort"? weil es mir in der jetzigen Form keinen Sinn macht. – SilentGhost

+0

Ich denke, die wirkliche Frage ist, muss es rekursiv sein, um den Job zu machen? Gibt es hier eine Rekursionsanforderung? –

Antwort

11

Dies ist nicht rekursiv, aber ich denke, es tut, was Sie wollen.

doc = 'a b c d e f' 
words = doc.split(None) 
max = 3   


for index in xrange(len(words)):  
    for n in xrange(max): 
     if index + n < len(words):   
      print ' '.join(words[index:index+n+1]) 

Und hier ist eine rekursive Lösung:

def find_terms(words, max_words_per_term):  
    if len(words) == 0: return [] 
    return [" ".join(words[:i+1]) for i in xrange(min(len(words), max_words_per_term))] + find_terms(words[1:], max_words_per_term) 


doc = 'a b c d e f' 
words = doc.split(None) 
for term in find_terms(words, 3): 
    print term 

Hier ist die rekursive Funktion wieder mit einigen erklärenden Variablen und Kommentare.

def find_terms(words, max_words_per_term): 

    # If there are no words, you've reached the end. Stop.  
    if len(words) == 0: 
     return []  

    # What's the max term length you could generate from the remaining 
    # words? It's the lesser of max_words_per_term and how many words 
    # you have left.               
    max_term_len = min(len(words), max_words_per_term)  

    # Find all the terms that start with the first word. 
    initial_terms = [" ".join(words[:i+1]) for i in xrange(max_term_len)] 

    # Here's the recursion. Find all of the terms in the list 
    # of all but the first word. 
    other_terms = find_terms(words[1:], max_words_per_term) 

    # Now put the two lists of terms together to get the answer. 
    return initial_terms + other_terms 
+0

Es sieht so aus, als müsste ich die erste von Ihnen bereitgestellte Lösung verwenden. Python wird eine Funktion nicht mehr als 999 Mal wiederholen lassen. Mein Testdokument hatte ungefähr 1750 Wörter und es ist auf der kleinen Seite. – tgray

+0

Das macht Sinn. Die rekursive Lösung hat Spaß gemacht, aber nicht wirklich praktisch. –

+0

Wenn Sie wirklich eine tiefe Rekursion wünschen, können Sie das Rekursionslimit mit sys.setrecursionlimit erhöhen. Aber die iterative Lösung ist hier wahrscheinlich besser. – Kiv

3

Ich würde vorschlagen, dass Sie Ihre Funktion zu einem Generator machen und dann die erforderliche Anzahl von Begriffen generieren. Sie müssten print zu yield ändern (und natürlich die ganze Blockfunktion ausführen).

Sie können sich auch itertools Modul ansehen, es ist ziemlich nützlich für eine Art von Arbeit, die Sie tun.

3

Warum machst du das? Sie können stattdessen nur eine for-Schleife und itertools.combinations() verwenden.

+0

Guter Vorschlag, aber ich muss den Auftrag erhalten bleiben. Beispiel: "a b c" erzeugt ["a", "b", "a b", "c", "b c", "a b c"], aber nicht "b a" oder "c b a". – tgray

+0

Es bewahrt die Ordnung. –

+0

Sorry für die Verwirrung, es sollte auch keine Wörter überspringen. Der Doc "Der schnelle braune Fuchs sprang über den Zaun" sollte keinen "braunen Zaun" als Bezeichnung haben. Gibt es eine Möglichkeit, itertools zu verwenden? – tgray

1

Was Sie suchen, ist N-Gram-Algorithmus. Das gibt dir [a, ab, b, bc, c, cd, ...].