2013-10-30 8 views
13

Ho estratto l'elenco di frasi da un documento. Sto pre-elaborando questo elenco di frasi per renderlo più sensato. Mi trovo di fronte con il seguente problemafissando parole con spazi usando un dizionario cerca in python?

Ho frasi quali "more recen t ly the develop ment, wh ich is a po ten t "

vorrei correggere tali frasi usando un dizionario guardare in alto? per rimuovere gli spazi indesiderati.

L'output finale dovrebbe essere "more recently the development, which is a potent "

Parto dal presupposto che questo è un compito dritto in avanti nel testo pre-elaborazione? Ho bisogno di aiuto con alcune indicazioni per cercare tali approcci. Grazie.

risposta

5

Dai un'occhiata alla parola o al testo segmentation. Il problema è trovare la divisione più probabile di una stringa in un gruppo di parole. Esempio:

thequickbrownfoxjumpsoverthelazydog 

La segmentazione più probabile dovrebbe essere naturalmente:

the quick brown fox jumps over the lazy dog 

Ecco un articolo compreso il codice sorgente prototipo per il problema utilizzando Google Ngram corpus:

La chiave per questo algoritmo per funzionare è l'accesso alla conoscenza del mondo, in questo caso le frequenze delle parole in alcune lingue. Ho implementato una versione dell'algoritmo descritto nell'articolo qui:

Esempio utilizzo:

$ python segmentation.py t hequi ckbrownfoxjum ped 
thequickbrownfoxjumped 
['the', 'quick', 'brown', 'fox', 'jumped'] 

Utilizzando i dati, anche questo può essere riordinati:

$ python segmentation.py lmaoro fll olwt f pwned 
lmaorofllolwtfpwned 
['lmao', 'rofl', 'lol', 'wtf', 'pwned'] 

Si noti che l'algoritmo è piuttosto lento - è prototypica l.

Un altro approccio utilizza NLTK:

Per quanto riguarda il tuo problema, si può solo concatenare tutte le parti degli archi si deve ottenere una singola stringa e la corsa di un algoritmo di segmentazione su di esso.

+3

Ma come funziona quando le frasi possono essere organizzate in più di un ordine? "Pen is mig htier tha n sw ord" – DhruvPathak

+1

Approccio elegante, ma scartare tutti gli spazi lo trasforma in un problema più difficile. La descrizione OPS ("rimuovere gli spazi indesiderati") suggerisce che gli spazi non mancano mai; se questo è corretto, non si dovrebbe mai guardare all'interno di un frammento per interruzioni di parole. – alexis

+1

@alexis, hai ragione, immagino che la performance possa essere migliorata almeno di un ordine di grandezza, calcolando solo le probabilità per i vari join invece di tutte le divisioni. Probabilmente tornerò più tardi per riformulare la mia risposta. – miku

2

Ecco qualcosa di veramente fondamentale:

chunks = [] 
for chunk in my_str.split(): 
    chunks.append(chunk) 
    joined = ''.join(chunks) 
    if is_word(joined): 
     print joined, 
     del chunks[:] 

# deal with left overs 
if chunks: 
    print ''.join(chunks) 

io suppone che si abbia un insieme di parole valide da qualche parte che possono essere utilizzati per implementare is_word. Devi anche assicurarti che si tratti di punteggiatura.Ecco un modo per farlo:

def is_word(wd): 
    if not wd: 
     return False 
    # Strip of trailing punctuation. There might be stuff in front 
    # that you want to strip too, such as open parentheses; this is 
    # just to give the idea, not a complete solution. 
    if wd[-1] in ',.!?;:': 
     wd = wd[:-1] 
    return wd in valid_words 
3

- Soluzione 1:

lascia pensare di questi pezzi nella tua frase come perline su un abaco, con ogni perla costituita da una stringa parziale, le perline può essere spostato a sinistra oa destra per generare le permutazioni. La posizione di ciascun frammento è fissata tra due frammenti adiacenti. Nel caso attuale, le perle sarebbe:

(more)(recen)(t)(ly)(the)(develop)(ment,)(wh)(ich)(is)(a)(po)(ten)(t) 

Questo risolve 2 sottoproblemi:

a) branello è una singola unità, in modo da non si preoccupano permutazioni nei tallone cioè permutazioni di "altri" non sono possibili

b) L'ordine delle perline è costante, cambia solo la spaziatura tra di esse. cioè "più" sarà sempre prima di "recen" e così via.

Ora, generare tutte le permutazioni di queste perle, che darà un output simile:

morerecentlythedevelopment,which is a potent 
morerecentlythedevelopment,which is a poten t 
morerecentlythedevelop ment, wh ich is a po tent 
morerecentlythedevelop ment, wh ich is a po ten t 
morerecentlythe development,whichisapotent 

Poi segnare queste permutazioni in base a quante parole dal dizionario rilevanti contengono, risultati più corretti possono essere facilmente filtrati su. more recently the development, which is a potent segnerà superiore morerecentlythedevelop ment, wh ich is a po ten t

codice che fa la parte di permutazione delle perline:

import re 

def gen_abacus_perms(frags): 
    if len(frags) == 0: 
     return [] 
    if len(frags) == 1: 
     return [frags[0]] 

    prefix_1 = "{0}{1}".format(frags[0],frags[1]) 
    prefix_2 = "{0} {1}".format(frags[0],frags[1]) 
    if len(frags) == 2: 
     nres = [prefix_1,prefix_2] 
     return nres 

    rem_perms = gen_abacus_perms(frags[2:]) 
    res = ["{0}{1}".format(prefix_1, x) for x in rem_perms] + ["{0} {1}".format(prefix_1, x) for x in rem_perms] + \ 
["{0}{1}".format(prefix_2, x) for x in rem_perms] + ["{0} {1}".format(prefix_2 , x) for x in rem_perms] 
    return res 



broken = "more recen t ly the develop ment, wh ich is a po ten t" 
frags = re.split("\s+",broken) 
perms = gen_abacus_perms(frags) 
print("\n".join(perms)) 

demo: http://ideone.com/pt4PSt


- Soluzione # 2 :

Suggerirei un approccio alternativo che utilizza l'analisi dell'analisi del testo già sviluppata da persone che lavorano su problemi simili e che hanno lavorato su un grande corpus di dati che dipende dal dizionario e dalla grammatica .e.g. motori di ricerca.

Non sono a conoscenza di tali apis pubblici/a pagamento, quindi il mio esempio si basa sui risultati di Google.

Proviamo a usare google:

  1. È possibile continuare a mettere i termini validi per Google, per passaggi multipli, e mantenere la valutazione dei risultati di un certo punteggio in base al dizionario di ricerca. qui ci sono due uscite importanti, utilizzando 2 passi del testo:

enter image description here

Questo outout viene utilizzato per un secondo passaggio:

enter image description here

che vi dà la conversione " "più recentemente lo sviluppo, che è un potente".

Per verificare la conversione, sarà necessario utilizzare un algoritmo di similarità e un punteggio per filtrare i risultati non validi/non validi.

Una tecnica grezza potrebbe utilizzare un confronto di stringhe normalizzate utilizzando difflib.

>>> import difflib 
>>> import re 
>>> input = "more recen t ly the develop ment, wh ich is a po ten t " 
>>> output = "more recently the development, which is a potent " 
>>> input_norm = re.sub(r'\W+', '', input).lower() 
>>> output_norm = re.sub(r'\W+', '', output).lower() 
>>> input_norm 
'morerecentlythedevelopmentwhichisapotent' 
>>> output_norm 
'morerecentlythedevelopmentwhichisapotent' 
>>> difflib.SequenceMatcher(None,input_norm,output_norm).ratio() 
1.0 
+1

il collo di bottiglia sarebbe il massimo di 100 query che è possibile inviare al libero google api =) – alvas

4

Il tuo obiettivo è migliorare il testo, non necessariamente renderlo perfetto; quindi l'approccio che hai delineato ha senso secondo me. Lo terrei semplice e userei un approccio "avido": inizia con il primo frammento e attaccalo fino a quando il risultato è nel dizionario; se il risultato non è, sputa quello che hai finora e ricomincia dal frammento successivo. Sì, occasionalmente commetti un errore con casi come the me thod, quindi se lo utilizzerai molto, potresti cercare qualcosa di più sofisticato. Tuttavia, probabilmente è abbastanza buono.

Principalmente quello che ti serve è un grande dizionario. Se la userete molto, la codificherei come "albero prefisso" (a.k.a. trie), in modo da poter scoprire rapidamente se un frammento è l'inizio di una parola reale. Il nltk fornisce un Trie implementation.

Poiché questo tipo di interruzioni di parole spurie sono incoerenti, estenderei anche il mio dizionario con parole già elaborate nel documento corrente; potresti aver visto la parola completa prima, ma ora è rotta.

+0

Un trie sarebbe una buona soluzione qui poiché si potrebbe verificare se il 't' dopo' recen' viene usato in uno dei nodi figlio (infatti, lo è) e quindi, è possibile unire gli algoritmi "salta spazi" e "trova parole possibili". –

3

Consiglierei di togliere gli spazi e cercare le parole del dizionario per suddividerle. Ci sono alcune cose che puoi fare per renderlo più preciso. Per fare in modo che ottenga la prima parola nel testo senza spazi, prova a prendere l'intera stringa e passa attraverso le parole del dizionario da un file (puoi scaricare diversi file dal http://wordlist.sourceforge.net/), quelli più lunghi prima di togliere le lettere dalla fine della stringa che vuoi segmentare. Se vuoi che funzioni su una grande stringa, puoi farlo automaticamente togliere le lettere dalla parte posteriore in modo che la stringa alla quale stai cercando la prima parola sia lunga quanto la parola più lunga del dizionario. Questo dovrebbe portare a trovare le parole più lunghe e rendere meno probabile fare qualcosa come classificare "asincrono" come "sincrono". Ecco un esempio che utilizza un ingresso prime a prendere nel testo per correggere e un file dizionario denominato dictionary.txt:

dict = open("dictionary.txt",'r')        #loads a file with a list of words to break string up into 
words = raw_input("enter text to correct spaces on: ") 
words = words.strip()           #strips away spaces 
spaced = []              #this is the list of newly broken up words 
parsing = True             #this represents when the while loop can end 
while parsing: 
    if len(words) == 0:           #checks if all of the text has been broken into words, if it has been it will end the while loop 
     parsing = False 
    iterating = True 
    for iteration in range(45):         #goes through each of the possible word lengths, starting from the biggest 
     if iterating == False: 
      break 
     word = words[:45-iteration]        #each iteration, the word has one letter removed from the back, starting with the longest possible number of letters, 45 
     for line in dict: 
      line = line[:-1]          #this deletes the last character of the dictionary word, which will be a newline. delete this line of code if it is not a newline, or change it to [1:] if the newline character is at the beginning 
      if line == word:          #this finds if this is the word we are looking for 
       spaced.append(word) 
       words = words[-(len(word)):]      #takes away the word from the text list 
       iterating = False 
       break 
print ' '.join(spaced)           #prints the output 

Se si vuole che sia ancora più accurato, si potrebbe provare a utilizzare un programma di analisi del linguaggio naturale , ci sono diversi disponibili per Python online gratuito.

2

È possibile scorrere un dizionario di parole per trovare la soluzione migliore. Aggiungere le parole insieme quando non viene trovata una corrispondenza.

def iterate(word,dictionary): 
    for word in dictionary: 
     if words in possibleWord: 
     finished_sentence.append(words) 
     added = True 
     else: 
     added = False 
     return [added,finished_sentence] 
sentence = "more recen t ly the develop ment, wh ich is a po ten t " 
finished_sentence = "" 
sentence = sentence.split() 
for word in sentence: 
    added,new_word = interate(word,dictionary) 
    while True: 
    if added == False: 
     word += possible[sentence.find(possibleWord)] 
     iterate(word,dictionary) 
    else: 
     break 
    finished_sentence.append(word) 

Questo dovrebbe funzionare. Per la variabile dictionary, scaricare un txt file di ogni singola parola inglese, quindi aprirlo nel programma.