Quale algoritmo fornisce suggerimenti in un correttore ortografico?


114

Quale algoritmo viene in genere utilizzato quando si implementa un controllo ortografico accompagnato da suggerimenti di parole?

All'inizio ho pensato che potesse avere senso controllare ogni nuova parola digitata (se non trovata nel dizionario) rispetto alla sua distanza di Levenshtein da ogni altra parola nel dizionario e restituire i risultati migliori. Tuttavia, sembra che sarebbe altamente inefficiente, dovendo valutare ripetutamente l'intero dizionario.

Come viene fatto in genere?

Risposte:


203

C'è un buon saggio di Peter Norvig su come implementare un correttore ortografico. È fondamentalmente un approccio di forza bruta che prova le stringhe candidate con una determinata distanza di modifica. ( Ecco alcuni suggerimenti su come migliorare le prestazioni del correttore ortografico utilizzando un filtro Bloom e un hashing candidato più veloce .)

I requisiti per un controllo ortografico sono più deboli. Devi solo scoprire che una parola non è nel dizionario. Puoi utilizzare un filtro Bloom per creare un correttore ortografico che consuma meno memoria. Una versione antica è descritta in Programming Pearls da Jon Bentley usando 64kb per un dizionario inglese.

Un BK-Tree è un approccio alternativo. Un bell'articolo è qui .

La distanza di Levenshstein non è esattamente la distanza di modifica corretta per un correttore ortografico. Conosce solo l'inserimento, la cancellazione e la sostituzione. La trasposizione è mancante e produce 2 per una trasposizione di 1 carattere (è 1 cancellazione e 1 inserimento). La distanza Damerau – Levenshtein è la distanza di modifica corretta.


2
+1 per il riferimento BK-Tree relativamente sconosciuto. È così che le aziende come Google, che lavorano con quantità di dati Real-World [TM], lo stanno facendo.
NoozNooz42

2
C'è una spiegazione molto migliore di BK-Trees qui .
Ian Boyd

17

Un approccio per generare suggerimenti che ho usato con successo ma che non ho mai visto descritto da nessuna parte è quello di pre-calcolare i suggerimenti (durante la creazione del dizionario) utilizzando funzioni hash "cattive".

L'idea è di esaminare i tipi di errori di ortografia commessi dalle persone e di progettare funzioni hash che assegnerebbero un'ortografia errata allo stesso bucket della sua ortografia corretta.

Ad esempio, un errore comune è usare la vocale sbagliata, come definire invece di definito . Quindi si progetta una funzione hash che tratta tutte le vocali come la stessa lettera. Un modo semplice per farlo è prima "normalizzare" la parola in ingresso e poi inserire il risultato normalizzato attraverso una normale funzione hash. In questo esempio, la funzione di normalizzazione potrebbe eliminare tutte le vocali, quindi definitediventa dfnt. La parola "normalizzata" viene quindi sottoposta a hashing con una tipica funzione hash.

Inserisci tutte le parole del tuo dizionario in un indice ausiliario (tabella hash) usando questa speciale funzione hash. I bucket in questa tabella avranno elenchi di collisioni più lunghi perché la funzione hash è "cattiva", ma questi elenchi di collisioni sono essenzialmente suggerimenti precalcolati.

Ora, quando trovi una parola con errori di ortografia, cerchi negli elenchi di collisioni il bucket a cui è associato l'errore di ortografia negli indici ausiliari. Ta da: Hai un elenco di suggerimenti! Tutto quello che devi fare è classificare le parole su di esso.

In pratica, avrai bisogno di alcuni indici ausiliari con altre funzioni hash per gestire altri tipi di errori, come lettere trasposte, lettere singole / doppie e persino uno semplicistico simile a Soundex per catturare errori di ortografia fonetici. In pratica, ho trovato quelle di pronuncia semplicistiche per fare molto e sostanzialmente obsolete alcune di quelle progettate per trovare errori di battitura banali.

Quindi ora cerchi gli errori di ortografia in ciascuno degli indici ausiliari e concatena le liste di collisione prima della classifica.

Ricorda che le liste di collisione contengono solo parole che sono nel dizionario. Con approcci che provano a generare ortografie alternative (come nell'articolo di Peter Norvig), puoi ottenere (decine di) migliaia di candidati che devi prima filtrare nel dizionario. Con l'approccio precalcolato, ottieni forse un paio di centinaia di candidati e sai che sono tutti scritti correttamente, quindi puoi saltare direttamente alla classifica.

Aggiornamento : da allora ho trovato una descrizione di algoritmo simile a questa, la FAROO Distributed Search . Questa è ancora una ricerca limitata a distanza di modifica, ma è molto veloce perché il passaggio di pre-calcolo funziona come la mia idea di "funzioni hash difettose". FAROO utilizza solo un concetto limitato di una cattiva funzione hash.


Grazie per aver fatto riferimento all'algoritmo SymSpell di Faroos. Sebbene entrambi gli algoritmi stiano pre-calcolando possibili errori di battitura e utilizzando una tabella hash per una rapida ricerca, la differenza principale è che SymSpell garantisce di rilevare tutti i possibili errori di ortografia fino a una certa distanza di modifica (a questo proposito SymSpell è equivalente all'algoritmo di Peter Norvig, solo 3..6 ordini di grandezza più veloci), mentre il tuo algoritmo utilizza un approccio euristico che rileverà solo un sottoinsieme limitato di tutti gli errori di ortografia teoricamente possibili (quindi il tuo costo di pre-calcolo potrebbe essere inferiore).
Wolf Garbe

L'algoritmo SymSpell pre-calcola e memorizza esplicitamente possibili errori di battitura, il mio schema "hash cattivo" no. Per l'inglese, è banale aggiungere un solo hash fonetico semplicistico che copra molto terreno (ad esempio, "terradacktle" -> "pterodactyl", che ha una distanza di modifica di 6). Certo, se hai bisogno di ricerche multilingue, potrebbe essere molto più difficile.
Adrian McCarthy

Assolutamente, sfruttando la conoscenza empirica dei probabili errori di battitura (e limitandoli a questi) risparmi tempo e spazio prima del calcolo. Ma per coprire tutti i possibili errori di ortografia SymSpell deve pre-calcolare solo una piccola parte di essi. Una parola di 5 lettere ha circa 3 milioni di possibili errori di ortografia entro una distanza di modifica massima di 3, ma con SymSpell è necessario pre-calcolare e memorizzare solo 25 eliminazioni. Questo è importante per la ricerca fuzzy / similarità oltre la correzione ortografica dove non esiste alcuna conoscenza empirica.
Wolf Garbe

7

Algoritmo

  1. Prendi come input una parola scritta in modo errato.
  2. Memorizza l'elenco delle parole inglesi insieme alle loro frequenze in un file di testo.
  3. Inserisci tutte le parole inglesi disponibili (memorizzate nel file di testo) insieme alle loro frequenze (misura della frequenza con cui una parola viene utilizzata in lingua inglese) in un albero di ricerca ternario.
  4. Ora attraversa lungo l'albero di ricerca ternario -
    • Per ogni parola incontrata nell'albero di ricerca ternario, calcola la sua distanza Levensthein dalla parola scritta erroneamente.
    • Se Levensthein Distance <= 3, memorizzare la parola in una coda prioritaria.
    • Se due parole hanno la stessa distanza di modifica, quella con la frequenza più alta è maggiore. Stampa i primi 10 elementi dalla coda prioritaria.

Ottimizzazione

  1. È possibile eliminare le parole nel sottoalbero del nodo corrente se la distanza di modifica della sottostringa della parola in ingresso dalla parola corrente è maggiore di 3.
    Puoi trovare la spiegazione più dettagliata e il codice sorgente sul progetto GitHub .

Hmm, la distanza di Levenshtein da "grattugia" a "maggiore" in questo caso non sarebbe sufficiente, poiché anche "grattugia" è una parola del dizionario. ;-)
Tony Brasunas

1
@ TonyBrasunas, Sì, hai ragione. Ma il programma restituirà effettivamente un elenco di 10 parole in caso di "grattugia" come input e suggerirà "grattugia" con distanza di modifica di 0 e anche "maggiore" con distanza di modifica di 1. Il che potrebbe essere di qualche aiuto. ;)
amarjeetAnand

Se un candidato ha una distanza di 2, ma è estremamente frequente, e un altro candidato ha una distanza di 1 ma è estremamente raro, come si classificano i due? Nell'approccio di cui sopra, l'oggetto raro vincerebbe sempre, è questo il risultato giusto?
speedplane

@speedplane Sì. il raro vincerà. E penso che sia il risultato giusto. Perché quella che ci aspettiamo è la parola più vicina, in base all'ortografia della parola in ingresso. Se sei ancora in dubbio, pensa in questo modo --- supponiamo che ci sia una parola rara che l'utente ha digitato correttamente. Ora la sua distanza è 0 ma la frequenza è molto bassa. Ora nei suggerimenti, dovremmo elencare questa parola rara (con distanza 0) in alto (perché la minima modifica della distanza vince) e altre parole con distanza 1-2-3, sotto.
amarjeetAnand

3

Non è necessario conoscere la distanza di modifica esatta per ogni parola nel dizionario. È possibile interrompere l'algoritmo dopo aver raggiunto un valore limite ed escludere la parola. Ciò ti farà risparmiare molto tempo di elaborazione.


1

Il controllo ortografico è molto facile da implementare come nel programma ortografico Unix. Il codice sorgente è disponibile in pubblico. La correzione può essere coinvolta, una tecnica è fare modifiche e controllare di nuovo se questa nuova parola è nel dizionario. Tali nuove modifiche possono essere raggruppate e mostrate all'utente.

Il sistema Unix utilizza un programma scritto da Mc IllRoy. Un modo alternativo è usare un Trie che può essere utile nel caso di file di grandi dimensioni.

L'approccio unix richiede molto meno spazio per un dizionario enorme poiché utilizza l'algoritmo di hash scatter.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.