Empecemos conociendo un poco la parte teórica :
¿Cómo funciona?
Dada una palabra, estamos tratando de elegir la corrección ortográfica más probable para esa palabra(puede darse el caso en que la "corrección", sea la palabra original). No hay manera de saber con seguridad (ejemplo: "abarar" debe ser corregido por :"abarrar" o "abarraz"), lo que sugiere que usemos probabilidades. Vamos a decir que estamos tratando de encontrar la corrección C, de todas las correcciones posibles, tal corrección bebe tener la mayor probabilidad dada la palabra original W.
Max P(C|W) (1)
Usando el Teorema de Bayes, la expresión (1) es equivalente a :
Max P(C|W)= Max P(W|C)*P(C)/P(W) (2)
como P(w) es el mismo para todos los C posibles, se puede obviar, obteniendo de (2):
Max P(C|W)= Max P(W|C)*P(C) (3)
Entendamos a mayor detalle la expresión (3):
- P(W), ¿cual es la probabilidad de que sea exactamente lo que se escribió?
- P(C), dado un remplazo C, ¿cual es la probabilidad de que sea esa?, ejemplo: P ("la") tendría una probabilidad relativamente alta, mientras que P ("zxzxzxzyyy") sería cercano a cero.
- P(W|C), ¿Cual es la probabilidad de que haya puesto W queriendo poner C?
Queremos la palabra C mas probable que se parezca a W
- Si es muy distinta de W, C no nos sirve (ejem : W=berde, C=hola)
- Si es muy rara, no nos sirve (ejem: W=verdo, C=bardo)
- Si es común y parecida, C es genial (ejm: W=verda, C= verde)
Código Completo
#! /usr/bin/env python26
#-*- coding: utf-8 -*-
import re, collections
def words(text):
"""
Escoje todas las palabras del text
"""
return re.findall(u'[\xf1\xe1\xe9\xed\xf3\xfaa-z]+', unicode(text.lower(), 'utf-8'))
def train(features):
"""
calcula el P(C)
"""
model = collections.defaultdict(lambda: 1)
for f in features:
model[f] += 1
list = []
return model
NWORDS = train(words(file('DicEspaniol.txt').read()))
alphabet = u'abcdefghijklmnopqrstuvwxyz\xf1\xe1\xe9\xed\xf3\xfa'
def edits1(word):
"""
Calcula el P(W/C) ----- distancia=1
"""
s = [(word[:i], word[i:]) for i in range(len(word) + 1)]
deletes= [a + b[1:] for a, b in s if b]
transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b) > 1]
replaces= [a + c + b[1:] for a, b in s for c in alphabet if b]
inserts= [a + c + b for a, b in s for c in alphabet]
return set(deletes + transposes + replaces + inserts)
def known_edits2(word):
"""
Calcula el P(W/C) ----- distancia=2 y se descarta si P(C)=0#-*- coding: utf-8 -*-
import re, collections
def words(text):
"""
Escoje todas las palabras del text
"""
return re.findall(u'[\xf1\xe1\xe9\xed\xf3\xfaa-z]+', unicode(text.lower(), 'utf-8'))
def train(features):
"""
calcula el P(C)
"""
model = collections.defaultdict(lambda: 1)
for f in features:
model[f] += 1
list = []
return model
NWORDS = train(words(file('DicEspaniol.txt').read()))
alphabet = u'abcdefghijklmnopqrstuvwxyz\xf1\xe1\xe9\xed\xf3\xfa'
def edits1(word):
"""
Calcula el P(W/C) ----- distancia=1
"""
s = [(word[:i], word[i:]) for i in range(len(word) + 1)]
deletes= [a + b[1:] for a, b in s if b]
transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b) > 1]
replaces= [a + c + b[1:] for a, b in s for c in alphabet if b]
inserts= [a + c + b for a, b in s for c in alphabet]
return set(deletes + transposes + replaces + inserts)
def known_edits2(word):
"""
"""
return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)
def known(words):
"""
Descarta si P(C)=0
"""
return set(w for w in words if w in NWORDS)
def correct(word):
"""
funcion principal
"""
word = unicode(word.lower(), 'utf-8')
candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
return max(candidates, key = NWORDS.get).encode('utf-8')
print correct("categoria")