Pregunta

Estoy trabajando en una solución para dividir largas líneas de jemer (el idioma camboyano) en palabras individuales (en UTF-8). Khmer no usa espacios entre palabras. Hay algunas soluciones por ahí, pero están lejos de ser adecuadas (aquí y aquí), y esos proyectos han quedado en el camino.

Aquí hay una línea de muestra de Khmer que debe dividirse (pueden ser más largas que esto):

ចូរសរសើរដល់ទ្រង់ដែលទ្រង់បានប្រទានការទាំងអស់នោះមកដល់រូបអ្នកដោយព្រោះអង្គព្រះយេស៊ូវ ហើយដែលអ្នកមិនអាចរកការទាំងអស់នោះដោយសារការប្រព្រឹត្តរបស់អ្នកឡើយ។

El objetivo de crear una solución viable que divida las palabras jmer es doble: alentará a quienes usan las fuentes Legacy (no Unicode) a convertir a Unicode (que tiene muchos beneficios), y permitirá importar las fuentes de Khmer. en unicode para ser utilizado con un corrector ortográfico rápidamente (en lugar de pasar y dividir manualmente palabras que, con un documento grande, pueden llevar mucho tiempo).

No necesito una precisión del 100%, pero la velocidad es importante (especialmente porque la línea que debe dividirse en palabras jmer puede ser bastante larga). Estoy abierto a sugerencias, pero actualmente tengo un gran corpus de palabras jmer que se dividen correctamente (con un espacio no roto), y he creado un archivo de diccionario de probabilidad de palabras (frecuencia.csv) para usar como diccionario para el diccionario para el diccionario para el diccionario para el diccionario para el diccionario para el diccionario para el diccionario. divisor de palabras.

Encontré este código de pitón aquí que usa el Algoritmo de Viterbi Y supuestamente corre rápido.

import re
from itertools import groupby

def viterbi_segment(text):
    probs, lasts = [1.0], [0]
    for i in range(1, len(text) + 1):
        prob_k, k = max((probs[j] * word_prob(text[j:i]), j)
                        for j in range(max(0, i - max_word_length), i))
        probs.append(prob_k)
        lasts.append(k)
    words = []
    i = len(text)
    while 0 < i:
        words.append(text[lasts[i]:i])
        i = lasts[i]
    words.reverse()
    return words, probs[-1]

def word_prob(word): return dictionary.get(word, 0) / total
def words(text): return re.findall('[a-z]+', text.lower()) 
dictionary = dict((w, len(list(ws)))
                  for w, ws in groupby(sorted(words(open('big.txt').read()))))
max_word_length = max(map(len, dictionary))
total = float(sum(dictionary.values()))

También intenté usar el código Java de origen del autor de esta página: Segmentación de texto: división de palabras basada en el diccionario Pero funcionó demasiado lento para ser de alguna utilidad (porque mi diccionario de probabilidad de palabras tiene más de 100k términos ...).

Y aquí hay otra opción en Python de Detectar palabras más probables del texto sin espacios / palabras combinadas:

WORD_FREQUENCIES = {
    'file': 0.00123,
    'files': 0.00124,
    'save': 0.002,
    'ave': 0.00001,
    'as': 0.00555
}

def split_text(text, word_frequencies, cache):
    if text in cache:
        return cache[text]
    if not text:
        return 1, []
    best_freq, best_split = 0, []
    for i in xrange(1, len(text) + 1):
        word, remainder = text[:i], text[i:]
        freq = word_frequencies.get(word, None)
        if freq:
            remainder_freq, remainder = split_text(
                    remainder, word_frequencies, cache)
            freq *= remainder_freq
            if freq > best_freq:
                best_freq = freq
                best_split = [word] + remainder
    cache[text] = (best_freq, best_split)
    return cache[text]

print split_text('filesaveas', WORD_FREQUENCIES, {})

--> (1.3653e-08, ['file', 'save', 'as'])

Soy un novato en lo que respecta a Python y soy realmente nuevo en toda programación real (fuera de los sitios web), así que por favor tengan paciencia conmigo. ¿Alguien tiene alguna opción que sienta que funcionaría bien?

¿Fue útil?

Solución

La biblioteca de la UCI (que tiene Pitón y ataduras de Java) tiene un Infractor de diccionario clase que se puede usar para esto.

Otros consejos

El pitón con ejemplo filesaveas parece recurrir a través de toda la cadena de entrada (for i in xrange(1, len(text) + 1)), rellenando los mejores resultados en el cache por el camino; en cada palabra potencial, después comienza a mirar el Siguiente palabra (que a su vez verá la palabra después de eso, y así sucesivamente), y si esa segunda palabra no se ve muy bien, no guardará esa en particular. Eso siente Como el tiempo de ejecución o (n!), donde n es la longitud de la cadena de entrada.

Súper inteligente, pero probablemente horrible para cualquier cosa que no sean tareas simples. ¿Cuál es la palabra jemer más larga que tienes? Espero <20 personajes.

Tal vez si alimenta la entrada en ese ejemplo de 20 caracteres a la vez, puede mantener el tiempo de ejecución en baja a algo que se acerca razonable. Alimente en los primeros 20 caracteres, chupe la primera palabra y luego alimente la entrada restante. Si reutiliza el caché, podría hacer algo tonto como almacenar palabras parciales en el camino.

En una táctica completamente diferente, ¿cuántas palabras jemer se forman concatenando dos o más palabras legales jemer? (Similar a 'Penknife' o 'Basketball'), si no demasiados, podría tener sentido crear un conjunto de diccionarios, segregados por la longitud de la palabra, mapeo de palabra a probabilidad de uso.

Digamos, la palabra más larga jemer tiene 14 caracteres; alimentarse en 14 caracteres de entrada al len14 Diccionario, almacene la probabilidad. Alimentarse en 13 caracteres a len13, almacene la probabilidad. Alimentarse en 12 caracteres ... todo el camino hasta 1 en len1. Luego elija la interpretación con la mayor probabilidad, guarde la palabra, quite tantos personajes e intente nuevamente.

Entonces, no fallará mal para las entradas como la imagen "I" VS ", ¿tal vez las entradas más largas deberían tener probabilidades infladas automáticamente?

Gracias por la divertida pregunta;) No conocía ningún idioma como este, genial.

Creo que esta es una buena idea, como es.

Le sugiero que, cuando tenga algo de experiencia con él, agregue algunas reglas, que pueden ser muy específicas, por ejemplo, dependiendo de la palabra antes, dependiendo de la palabra después, dependiendo de las palabras circundantes, dependiendo de una secuencia de palabras antes de la corriente palabra, solo para enumerar los más frecuentes. Puede encontrar un conjunto de reglas en el proyecto gposttl.sf.net, que es un proyecto de etiquetado POS, en el archivo data/contextualRuleFile.

Las reglas deben usarse después de que se termine la evaluación de estadísticas, hacen un poco de ajuste fino y pueden mejorar notablemente la precisión.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top