Cómo implementar un corrector de ortografía
Cómo implementar un corrector de ortografía
En el año 2007 Peter Norvig, director de investigaciones en Google, escribió un artículo en su blog llamado "How to Write a Spelling Corrector". He tratado de adaptarlo en español usando el corpus de las palabras y sus frecuencias en español extraído de la página de la Real Academia de la Lengua. El corpus de referencia del español actual (CREA) se puede consultar aquí.
La corrección de ortografía es un área de investigación del procesamiento natural del lenguaje (PNL) que usa la lingüística, la informática y la inteligencia artificial para que las máquinas decodifiquen el lenguaje humano. Los errores comunes en español pueden ser: omisión, transposición, adición o remplazo de letras. Un ejemplo de transposición pude ser "cuidad" por "ciudad", de omisión "sempre" por "siempre", de adición "enrroque" por "enroque". Hay que incluir el mal uso de las tildes en español que es un problema que no se ve en el idioma inglés.
El CREA contiene 737799 palabras con sus respectivas frecuencias absolutas y normalizadas.
Orden Frec.absoluta Frec.normalizada
1. de 9,999,518 65545.55
2. la 6,277,560 41148.59
3. que 4,681,839 30688.85
4. el 4,569,652 29953.48
5. en 4,234,281 27755.16
6. y 4,180,279 27401.19
7. a 3,260,939 21375.03
8. los 2,618,657 17164.95
9. se 2,022,514 13257.31
10. del 1,857,225 12173.87
Luego de determinar que la suma total de las frecuencias es 134404155 y de modificar el archivo anterior a la siguiente forma:
de 9999518
la 6277560
que 4681839
el 4569652
en 4234281
y 4180279
a 3260939
los 2618657
se 2022514
del 1857225
Si llamamos a este nuevo archivo frecuencias.txt, podemos crear un diccionario de frecuencias y combinarlo con el código que usa Peter Norvig:
N = 134404155.0 # suma de todas las frecuencias absolutas
PALABRAS = dict()
with open('frecuencias.txt', 'r') as datafile:
for line in datafile:
valores = line.strip('\n').split()
PALABRAS[valores[0]] = int(valores[1])
def P(palabra, N=sum(PALABRAS.values())):
"Probabilidad de `palabra`."
return PALABRAS[palabra] / N
def correccion(palabra):
"Corrección más probable de una palabra."
return max(candidatos(palabra), key=P)
def candidatos(palabra):
"Genera posibles correcciones para una palabra."
return (conocidas([palabra]) or conocidas(edicion1(palabra)) or conocidas(edicion2(palabra)) or [palabra])
def conocidas(palabras):
"El subconjunto de `palabras` que aparecen en el diccionario de PALABRAS."
return set(w for w in palabras if w in PALABRAS)
def edicion1(palabra):
"Todas las ediciones que están a una edición de `palabra`."
letras = 'abcdefghijklmnopqrstuvwxyzáéíóúüñ'
divisiones = [(palabra[:i], palabra[i:]) for i in range(len(palabra) + 1)]
omisiones = [L + R[1:] for L, R in divisiones if R]
transposiciones = [L + R[1] + R[0] + R[2:] for L, R in divisiones if len(R)>1]
remplazos = [L + c + R[1:] for L, R in divisiones if R for c in letras]
inserciones = [L + c + R for L, R in divisiones for c in letras]
return set(omisiones + transposiciones + remplazos + inserciones)
def edicion2(palabra):
"Todas las ediciones que están a dos ediciones de `palabra`."
return (e2 for e1 in edicion1(palabra) for e2 in edicion1(e1))
Se agregaron las letras adicionales áéíóúüñ usadas en español.
Estos son ejemplos del resultado de la función correccion:
>>> correccion('domigno')
'domingo'
>>> correccion('luness')
'lunes'
>>> correccion('miércole')
'miércole'
>>> correccion('juves')
'jueves'
>>> correccion('vieernek')
'viernes'
Como se puede ver el corrector no corrige bien la tercera palabra por lo que habría que revisar el código para esos casos.